如何在存储过程内部将字符串传递到动态sql中

时间:2018-07-06 10:27:33

标签: c# sql sql-server validation stored-procedures

截止到现在,我有一条这样的SQL语句:

SELECT 
    y.ID, y.STATUS, y.CONTROLID, y.TRCDE
FROM 
    YTDTRNI AS y 
LEFT JOIN 
    VND AS v ON y.COMNO = v.COMNO 
WHERE 
    TRCDE ='RC' 
ORDER BY 
    ID DESC

我正在尝试在使用动态SQL的存储过程中使用此查询。到目前为止,我的存储过程如下:

SET @query =  N'SELECT y.ID, y.STATUS, y.CONTROLID, y.TRCDE
                FROM YTDTRNI AS y LEFT JOIN VND AS v ON y.COMNO = v.COMNO 
                WHERE TRCDE = ' + @searchtrtype + ' 
                ORDER BY ' + @orderbycondition

变量@searchtrtype@orderbycondition的类型为nvarchar

我正在使用ASP.NET/C#程序来调用存储过程。但是,它有一个例外:

  

在期望条件靠近“ ORDER”的上下文中为非布尔类型的表达式

我认为我得到了错误,因为在@query变量内部未正确连接或格式化字符串值。

接受任何建议。

编辑:目前我的存储过程如下:

enter image description here

当我执行存储过程时,它返回我想要的结果集,但它还会显示一条错误消息:

  

必须声明标量变量“ @dsearchtrtype”。

我尝试在BEGIN主体中声明它,并将其声明为存储过程的参数的一部分,但仍显示相同的消息。

4 个答案:

答案 0 :(得分:4)

了解如何通过sp_executesql使用参数。您可以针对@searchtrtype进行此操作,但不能针对@orderbycondition进行此操作:

SET @query =  N'
SELECT y.ID, y.STATUS,y.CONTROLID,y.TRCDE
FROM YTDTRNI y LEFT JOIN
     VND v
     ON y.COMNO = v.COMNO 
WHERE TRCDE = @searchtrtype 
ORDER BY @orderbycondition';

SET @query = REPLACE(@query, '@orderbycondition', @orderbycondition);

EXEC sp_executesql @query,
                   N'@searchtrtype NVARCHAR(255)',   -- or whatever the right type is
                   @searchtrtype=@searchtrtype;

您不能传递标识符,只能传递值,因此不适用于@orderbycondition

答案 1 :(得分:1)

您需要参数化SQL。为SQL连接字符串是一个糟糕的主意。因为它使您易于注射。您想要的方式是:

DECLARE @query nvarchar(MAX);
SET @query =  N'SELECT y.ID,' + NCHAR(10) + 
              N'       y.STATUS,' + NCHAR(10) + 
              N'       y.CONTROLID,' + NCHAR(10) + 
              N'       y.TRCDE' + NCHAR(10) + 
              N'FROM YTDTRNI AS y' + NCHAR(10) + 
              N'     LEFT JOIN VND AS v ON y.COMNO = v.COMNO ' + NCHAR(10) + 
              N'WHERE TRCDE = @dsearchtrtype' + NCHAR(10) + 
              N'ORDER BY ' + QUOTENAME(@orderbycondition) + N';';
PRINT @SQL;

EXEC sp_executesql @query, N'@dsearchtrtype nvarchar(100)', @dsearchtrtype = @searchtrtype;

但是,由于您的变量@orderbycondition,这可能行不通。但是,我不知道它具有什么类型的值,如果它类似于'ID desc',它将变成ORDER BY [ID desc];

如果这个假设是正确的,我建议使用2个变量。一个用于排序列,一个用于方向,然后将动态SQl的最后一行替换为:

N'ORDER BY ' + QUOTENAME(@orderbycolumn) + N' ' + CASE WHEN @orderbydirection NOT IN(N'ASC',N'DESC') THEN N'' ELSE @orderbydirection END + N';';

如果您的@orderbycondition的值可能比这更复杂,请发表评论让我知道(并更详细地更新您的问题),我很乐意解释如何创建更具动态性的ORDER BY子句使用表类型参数,并通过使用STUFFFOR XML PATH将其添加到动态SQL中。

答案 2 :(得分:0)

根据提供的示例,看来OP只是想对单个列进行过滤,并对用户指定的列执行排序。可以通过参数化查询来实现,而无需动态SQL。

在where子句中,TRCDE字段可以直接分配给@searchtrtype参数。动态排序要求有些棘手,但可以通过在CASE子句中使用ORDER BY语句来实现。必须包含一个附加参数,以指示排序是升序还是降序。以下查询演示:

DECLARE @orderByColumn  NVARCHAR(50) = 'ID'; -- The column to sort by
DECLARE @sortAscending BIT = 1; -- Indicate sorting order 1 == Ascending, 0 == Descending
DECLARE @searchtrtype NVARCHAR(10) = 'RC'

IF @sortAscending = 1 -- Sort data in ascending order
BEGIN

    SELECT       y.[ID]
                ,y.[STATUS]
                ,y.[CONTROLID]
                ,y.[TRCDE]
    FROM        YTDTRNI AS y 
    LEFT JOIN   VND AS v ON y.[COMNO] = v.[COMNO]
    WHERE       TRCDE = @searchtrtype 
    ORDER BY    (
                    -- Create case statement for every column user may want to filter on
                    CASE
                        WHEN @orderByColumn = 'ID' THEN [ID]
                        ELSE NULL -- Simply return null if we are not ordering by this column, effectively ignore the column.
                    END
                 ),
                 (
                    CASE
                        WHEN @orderByColumn = 'STATUS' THEN [STATUS]
                        ELSE NULL -- Simply return null if we are not ordering by this column, effectively ignore the column.
                    END
                 ),
                             (
                    CASE
                        WHEN @orderByColumn = 'CONTROLID' THEN [CONTROLID]
                        ELSE NULL -- Simply return null if we are not ordering by this column, effectively ignore the column.
                    END
                 ) ASC;
END
ELSE
BEGIN
    SELECT       y.[ID]
                ,y.[STATUS]
                ,y.[CONTROLID]
                ,y.[TRCDE]
    FROM        YTDTRNI AS y 
    LEFT JOIN   VND AS v ON y.[COMNO] = v.[COMNO]
    WHERE       TRCDE = @searchtrtype 
    ORDER BY    (
                    CASE
                        WHEN @orderByColumn = 'ID' THEN [ID]
                        ELSE NULL -- Simply return null if we are not ordering by this column, effectively ignore the column.
                    END
                 ),
                 (
                    CASE
                        WHEN @orderByColumn = 'STATUS' THEN [STATUS]
                        ELSE NULL -- Simply return null if we are not ordering by this column, effectively ignore the column.
                    END
                 ),
                             (
                    CASE
                        WHEN @orderByColumn = 'CONTROLID' THEN [CONTROLID]
                        ELSE NULL -- Simply return null if we are not ordering by this column, effectively ignore the column.
                    END
                 ) DESC;
END

此方法工作量较大,但更易于故障排除,维护并保护您免受SQL注入的侵害。

答案 3 :(得分:-1)

您是否只需要包含转义的撇号。如果@searchtrtype可以包含撇号,则可能必须使用REPLACE(@searchtrtype,'''','''''')

对其进行转义
SET @query =  N'SELECT y.ID, y.STATUS,y.CONTROLID,y.TRCDE
FROM YTDTRNI AS y LEFT JOIN VND AS v ON y.COMNO = v.COMNO 
WHERE TRCDE = ''' + @searchtrtype + ''' 
ORDER BY ' + @orderbycondition