【问题标题】:How to pass in a string into dynamic sql inside a stored procedure如何将字符串传递到存储过程中的动态 sql
【发布时间】:2018-07-06 10:27:32
【问题描述】:

到目前为止,我有一个这样的 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 变量中的字符串值未正确连接或格式化。

愿意接受任何建议。

编辑:我的存储过程现在看起来像这样:

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

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

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

【问题讨论】:

  • 你有没有遗漏撇号?
  • 你能显示变量声明吗?还是完整的存储过程代码?
  • 小心SQL注入

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


【解决方案1】:

通过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

【讨论】:

  • 看来您对@orderbycondition 的担忧与我一样。
【解决方案2】:

您需要参数化您的 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 值可能比这更复杂,请发表评论让我知道(并更详细地更新您的问题),我很乐意解释如何创建一个更动态的 @987654327使用表类型参数的 @ 子句,以及使用 STUFFFOR XML PATH 将其添加到动态 SQL。

【讨论】:

  • 我已经尝试了你的方法,我快到了。当我执行存储过程时,它会返回我想要的结果集,但它也会显示一条错误消息:Must declare the scalar variable "@dsearchtrtype".
  • 听起来您正试图在动态 SQL 之外引用 @dsearchtrtype
【解决方案3】:

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

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

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 注入。

【讨论】:

    【解决方案4】:

    您是否只需要包含转义的撇号。如果@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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-04-03
      • 1970-01-01
      • 1970-01-01
      • 2019-10-20
      • 1970-01-01
      • 1970-01-01
      • 2022-07-13
      相关资源
      最近更新 更多