我有一个SQL语句,其中包含@StartRow, @StartEnd, @CategoryIds
等参数。
SELECT * FROM StackOverFlow
WHERE
StartRow = @StartRow
AND StartEnd = @StartEnd
AND CategoryId IN (@CategoryIds)
当我设置如下参数时:
DECLARE @StartRow INT = 1;
DECLARE @StartRow INT = 10;
DECLARE @CategoryId NVARCHAR(50);
set @CategoryId ='124,125'
失败的消息是:
将nvarchar值'124,125'转换为数据时转换失败 输入int。
当我手动设置SQL where语句时如下:
WHERE
StartRow = @StartRow
AND StartEnd = @StartEnd
AND CategoryId IN (124, 125)
有效。
如何解决转换问题?
答案 0 :(得分:3)
您需要使用dynamic SQL。所以你会写
DECLARE @StartRow INT = 1;
DECLARE @StartRow INT = 10;
DECLARE @CatogoryIds NVARCHAR(50);
SET @CatogoryIds = N'124, 125';
DECLARE @SQL NVARCHAR(MAX);
SET @SQL = N'
SELECT *
FROM StackOverFlow
WHERE
StartRow = ' + @StartRow +
N' AND StartEnd = ' + @StartEnd +
N' AND CategoryId IN (' + @CategoryIds + N');';
EXEC(@SQL);
GO
我希望这会有所帮助。
答案 1 :(得分:2)
如果使用动态SQL,则应使用参数化查询和SP_EXECUTESQL,如此
CREATE TABLE T (StartRow INT, StartEnd INT, CategoryID INT);
INSERT T VALUES (1, 10, 124), (1, 10, 125), (1, 10, 126);
DECLARE @StartRow INT = 1;
DECLARE @StartEnd INT = 10;
DECLARE @CategoryId NVARCHAR(50) ='124); DROP TABLE T; --';
DECLARE @SQL NVARCHAR(MAX);
SET @SQL = N'SELECT *
FROM T
WHERE StartRow = @Start
AND StartEnd = @End
AND CategoryID IN (' + @CategoryId + ')'
EXECUTE SP_EXECUTESQL @SQL, N'@Start INT, @End INT', @StartRow, @StartEnd;
<强> Dynamic SQL Example 强>
您可以使用SQL-Server的XML扩展在没有动态SQL的情况下执行此操作,但我不确定您是否一定要这样做,您可能需要运行一些测试来检查性能。
DECLARE @StartRow INT = 1;
DECLARE @StartEnd INT = 10;
DECLARE @CategoryId NVARCHAR(50) ='124,125';
DECLARE @X XML = CAST(N'<root><catid>' + REPLACE(@CategoryID, ',', '</catid><catid>') + '</catid></root>' AS XML);
SELECT StartRow,
StartEnd,
CategoryID
FROM T
INNER JOIN
( SELECT [CatID] = cat.value('.', 'int')
FROM @X.nodes('/root/catid') c (cat)
) c
ON c.CatID = CategoryID;
<强> Example using XML Extension 强>
查询基本上将逗号分隔的字符串转换为XML,然后将xml拆分为自己的表。
这也应该降低sql注入的风险,因为任何格式错误的字符串都会抛出错误而不是运行。考虑以下变量:
DECLARE @StartRow INT = 1;
DECLARE @StartEnd INT = 10;
DECLARE @CategoryId NVARCHAR(50) ='124,125); DROP TABLE T; --';
使用XML扩展方法运行将提供此
Msg 245, Level 16, State 1, Line 13
Conversion failed when converting the nvarchar value '124,125); DROP TABLE T; --' to data type int.
<强> SQL Injection Fail with XML Extensions 强>
使用动态SQL运行将获得所需的结果,但是下次运行它时,您将获得:
Msg 208, Level 16, State 1, Line 1
Invalid object name 'T'.
<强> SQL Injection Example 强>
还有其他分割字符串的方法而不是上面使用的XML方法,但是它只是为了演示动态SQL不是前进的唯一方法,如果你无法控制你的输入字符串那么它会更明智不是将其用作恶意字符串可能会破坏您的数据!
为了完整答案,您还可以使用表值参数。 e.g。
CREATE TYPE dbo.IntegerList AS TABLE (value INT);
CREATE PROCEDURE dbo.ExampleProcedure @StartRow INT, @StartEnd INT, @CategoryID dbo.IntegerList READONLY
AS
BEGIN
SELECT *
FROM T
WHERE StartRow = @StartRow
AND StartEnd = @StartEnd
AND CategoryID IN (SELECT Value FROM @CategoryID)
END