如果使用动态 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;
动态 SQL 示例
您可以使用 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;
使用 XML 扩展的示例
该查询基本上将您的逗号分隔字符串转换为 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.
XML 扩展的 SQL 注入失败
使用动态 SQL 运行会得到想要的结果,但是下次你运行它时,你会得到:
Msg 208, Level 16, State 1, Line 1
Invalid object name 'T'.
SQL 注入示例
除了上面使用的 XML 方法之外,还有其他拆分字符串的方法,但这只是为了证明动态 SQL 并不是唯一的前进方式,如果您无法控制输入字符串,那么不使用它会更明智因为恶意字符串会破坏您的数据!
为了答案的完整性,您还可以使用表值参数。例如
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