截止到现在,我有一条这样的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
主体中声明它,并将其声明为存储过程的参数的一部分,但仍显示相同的消息。
答案 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
子句使用表类型参数,并通过使用STUFF
和FOR 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