0

Мне нужно сохранить запрос как хранимую процедуру в SQL Server.Оператор WITH в динамическом sql

Мне также необходимо передать параметры, которые определяют имена таблиц и столбцов.

Это вопрос, который мне нравится, я попытался сохранить его в строке, а затем EXECUTE, но без успеха, хо я могу это решить?

CREATE PROCEDURE sp_selectAllParents @id int, @tableid varchar(30), @tablename varchar(30) 
AS BEGIN 
SET NOCOUNT ON; 
WITH ct AS (
    SELECT * FROM @tablename t WHERE @tableid = @id 
    UNION ALL 
    SELECT t.* FROM @tablename t JOIN ct ON t.parentId = [email protected] 
) 
SELECT * FROM @tablename t WHERE @tableid NOT IN (SELECT @tableid FROM ct) 
END 

EDIT: моей попытка была:

DECLARE @sql varchar(255) 
SET @sql = 'WITH ct AS (SELECT * FROM @tablename t WHERE @tableid = @id UNION ALL SELECT t.* FROM @tablename t JOIN ct ON t.parentId = [email protected]) SELECT * FROM @tablename t WHERE @tableid NOT IN (SELECT @tableid FROM ct)' 
EXEC(@sql) 
+3

Можете ли вы показать свою попытку? –

+4

У вас действительно есть так много разных таблиц с иерархической структурой, что необходима общая процедура для этого? Это чревато проблемами, и я бы подумал, что просто написать процедуру для каждой таблицы будет более безопасной и простой, а также меньше подверженности ошибкам (указаны недопустимые имена таблиц или столбцов). На несвязанной ноте вы должны [избегать prefex 'sp_' для своих собственных процедур] (http://sqlperformance.com/2012/10/t-sql-queries/sp_prefix). – GarethD

+0

Как правило, плохой идеей является создание хранимых процедур, которые принимают имя таблицы и/или имя столбца в качестве параметров для получения результатов. Вы должны пересмотреть свое решение. –

ответ

1

если ваши отправляет имя таблицы в качестве параметра в этом случае вам нужно создать динамическую строку запроса. может помочь ниже сценария

CREATE PROCEDURE sp_selectAllParents @id int, @tableid varchar(30), @tablename varchar(30) 
AS BEGIN 
SET NOCOUNT ON; 
SET @query=N'WITH ct AS (
    SELECT * FROM @tablename t WHERE @tableid = @id 
    UNION ALL 
    SELECT t.* FROM @tablename t JOIN ct ON t.parentId = [email protected] 
) 
    SELECT * FROM @tablename t WHERE @tableid NOT IN (SELECT @tableid FROM ct)' 

EXECUTE sp_executesql @query, @id,@tablename,@tableid 
END 
+0

@GarethD Да, получилось, спасибо –

3

Как я уже говорил в этом разделе, это плохая идея. Вы должны действительно переосмыслить свое решение.

хранимых процедур должны выглядеть следующим образом:

CREATE PROCEDURE selectAllParents @id int, @tableid sysname, @tablename sysname 
AS 
BEGIN 
SET NOCOUNT ON; 

-- Guards against SQL Injection attacks (replace ' with '') 
SET @tableid=REPLACE(@tableid,'''',''''''); 
SET @tablename=REPLACE(@tablename,'''',''''''); 

DECLARE @stmt NVARCHAR(4000); 
SET @stmt= 
    ';WITH ct AS ('+ 
    'SELECT * FROM ' + QUOTENAME(@tablename) + ' t WHERE ' + QUOTENAME(@tableid) + '= @id ' + 
    'UNION ALL ' + 
    'SELECT t.* FROM ' + QUOTENAME(@tablename) + ' t JOIN ct ON t.parentId = ct.' + QUOTENAME(@tableid) + 
    ')'+ 
    'SELECT * FROM ' + QUOTENAME(@tablename) +' t WHERE ' + QUOTENAME(@tableid) + ' NOT IN (SELECT ' + QUOTENAME(@tableid) +' FROM ct);'; 

EXEC sp_executesql 
    @stmt, 
    N'@id int', 
    @id; 
END 
GO 
+3

Я бы определенно использовал 'QUOTENAME' вокруг имен объектов здесь , и я, вероятно, использовал бы 'SYSNAME' как тип данных для параметров имени объекта. Возможно, стоит добавить проверку и проверку имени столбца и имени таблицы. Я знаю, что многое из этого выходит за рамки вопроса, однако, при предоставлении решения, о котором вы уже посоветовали, я думаю, что существует определенная обязанность по крайней мере смягчить ущерб, который может быть вызван его использованием. – GarethD

+0

@GarethD Защиты, имена и имена систем. –

+2

Бит замены охранников не требуется, так как quotename избегает всех этих действий и может фактически сделать недопустимым имя (но только если кто-то создал таблицу типа '[table'1]', и они, вероятно, заслуживают ошибки, если они). Я имел в виду нечто вроде: 'IF OBJECT_ID (@tablename, 'U') NULL RETURN; - ТАБЛИЦА НЕ СУЩЕСТВУЕТ СОСТОЯНИЕ', и 'ЕСЛИ COL_LENGTH (@tablename, @tableid) НЕВЕРНОЕ ВОЗВРАТ; - КОЛОНКА НЕ СУЩЕСТВУЕТ В ТАБЛИЦЕ SO EXIT', должно быть, было немного более ясно, Извините. – GarethD