我有一个使用动态SQL的存储过程。我的公司最近决定取消动态代码。
我在这里大大简化了我的观点; @PersonID
和@MhnNum
是存储过程的参数:
Declare @sql Varchar(max)
Set @sql="Select from tableA p"
If @PersonID Is Not Null
Set @sql = @sql + ' Where p.[ID] = ' + cast(@PersonID as varchar(12))
If @MhnNum Is Not Null
Set @sql = @sql + ' Where p.[MhnNum] = ' + '''' + cast(@MhnNum as varchar(12)) + ''''
是否有(简便的)方法来摆脱此动态SQL?
现在,我的解决方案是使用重复代码创建2个If。必须有一种更优雅的方法来进行此操作。
or
和and
的简单组合可以得到相同的结果:
Select *
From tableA
Where (@personId is null or id = @personId)
And (@MhnNum is null or whnNum =@mhnNum)
(写评论会很混乱)
您可以检查参数并采取相应措施。即:
Select from tableA p
where (@PersonID IS NULL or p.[ID] = @PersonID) and
(@MhnNum IS NULL or p.[MhnNum] = @MhnNum);
坦白说,动态SQL可能是您要走的路,因为您拥有一个全面的查询,而不是动态SQL。这是巨大的注射风险。参数化语句:
DECLARE @SQL nvarchar(MAX),
@CRLF nchar(2) = CHAR(13) + CHAR(10);
SET @SQL = N'SELECT *' + @CRLF +
N'FROM TableA A' + @CRLF +
CASE WHEN @PersonID IS NOT NULL THEN N'WHERE A.ID = @PersonID;'
WHEN @MhnNum IS NOT NULL THEN N'WHERE A.MhnNum = @MhnNum;'
END;
EXEC sys.sp_executesql @SQL, N'@PersonID int, @MhnNum int', @PersonID, @MhnNum;
使用非动态方法将导致不良查询计划的缓存,这是不希望的。
如果必须使用非动态SQL(由于无意义的公司政策,如果正确使用动态SQL不会有任何问题,然后添加OPTION RECOMPILE
:
IF @PersonID IS NOT NULL AND @MhnNum IS NOT NULL
THROW 68542, N'Both @PersonID and @MhnNum cannot be non-NULL values.', 11;
SELECT *
FROM TableA A
WHERE (A.ID = @PersonID OR @PersonID IS NULL)
AND (A.MhnNum = @MhnNum OR @MhnNum IS NULL)
OPTION (RECOMPILE);
THROW
在其中,因为如果您有2个非NULL
值,您的代码也会出错。