如何摆脱动态SQL(T-SQL)

问题描述 投票:0回答:3

我有一个使用动态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。必须有一种更优雅的方法来进行此操作。

sql sql-server tsql
3个回答
2
投票

orand的简单组合可以得到相同的结果:

Select *
From tableA
Where (@personId is null or id = @personId) 
And (@MhnNum is null or whnNum =@mhnNum)

1
投票

(写评论会很混乱)

您可以检查参数并采取相应措施。即:

Select from tableA p
where  (@PersonID IS NULL or p.[ID] = @PersonID) and
 (@MhnNum  IS NULL or p.[MhnNum] = @MhnNum);

1
投票

坦白说,动态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值,您的代码也会出错。

© www.soinside.com 2019 - 2024. All rights reserved.