在SQL Server存储过程SELECT语句中嵌套if语句

时间:2009-12-07 23:01:42

标签: sql-server-2005 stored-procedures nested

我是新来的,对存储过程比较新,所以请耐心等待!我在这里检查了相关问题,但在这个例子中找不到任何有用的东西。

我正在尝试构建一个存储过程(MS SQL Server 2005),该过程接受大量传入的值,实际上动态构建SQL,就像使用内联SQL一样。

这就是我失败的地方。

我们(为了清晰起见而略微简化):

@searchf1 varchar(100),   -- search filter 1
@searchr1 varchar(100),   -- search result 1
@searchf2 varchar(100),   -- search filter 2
@searchr2 varchar(100),   -- search result 2
@direction char(1),   -- direction to order results in
AS

set nocount on
set dateformat dmy

SELECT *
  FROM database.dbo.table T
 WHERE T.deleted = 'n'
ORDER BY CASE @direction
            WHEN 'A' THEN T.id
            WHEN 'D' THEN T.id DESC
         END

END

set nocount off

我也尝试过ORDER BY的行:

IF @direction = 'N' THEN
     ORDER BY 
          T.id
ELSE
     ORDER BY
          T.id DESC

这两种方法都给我一个错误:

“关键字'DESC'附近的语法不正确。” (引用最终ORDER BY之后的行ID DESC

作为此存储过程的一部分,我还想尝试输入匹配的值对,这些值引用要查找的字段和与之匹配的字段,这些值可以存在或者为''。为此,我需要在SELECT部分​​代码中添加类似于:

的代码
WHERE 
     deleted = 'n'
     IF @searchf1 <> '' THEN
         AND fieldf1 = @searchf1 AND fieldr1 = @searchr1

然而,这会产生如下错误:

关键字“IF”附近的语法不正确。

我知道这种类型的动态SQL并不是最优雅的。而且我知道我可以用glocal IF ELSE语句做到这一点,但是如果我这样做,那么SP会长达数千行;最多可以有15对这些搜索字段,以及指示该方向的方向和字段。

(此SP的当前版本使用传入的ID列表来返回由某些内联动态SQL生成的内容,通过执行此操作,我尝试将其减少为一次命中以生成记录集)

任何帮助非常感谢。为了清楚起见,我已经大大简化了上面例子中的代码,因为它是我正在询问的带有SELECT和ORDER BY的嵌套IF语句的一般概念。

3 个答案:

答案 0 :(得分:2)

为此我会尝试使用更正式的动态SQL解决方案,如下所示,给定您定义的输入参数

DECLARE @SQL VARCHAR(MAX)

SET @SQL = '
SELECT

FROM
     database.dbo.table T
WHERE
     T.deleted = ''n'' '

--Do your conditional stuff here
IF @searchf1 <> '' THEN
    SET @SQL = @SQL + ' AND fieldf1 = ' + @searchf1 + ' AND fieldr1 = ' + @searchr1 + ''' '

--Finish the query
SET @SQL = @SQL + ' ORDER BY xxx'

EXEC(@SQL)

免责声明: 动态SQL的使用不应该被轻视,并且应该在所有情况下都要正确考虑,以确保您不会对但是,SQL注入攻击对于某些动态搜索类型的操作来说,它是最优雅的路径之一。

答案 1 :(得分:2)

以这种方式尝试:

SELECT *  FROM database.dbo.table T WHERE T.deleted = 'n'
ORDER BY 
CASE WHEN @direction='A' THEN T.id END ASC,
CASE WHEN @direction='D' THEN T.id END DESC         

来源文章:
http://blog.sqlauthority.com/2007/07/17/sql-server-case-statement-in-order-by-clause-order-by-using-variable/

答案 2 :(得分:0)

根据字段的数据类型,如果不允许空值,您可能拥有的另一个选项是执行类似的操作。

SELECT * FROM database.dbo.table T. WHERE T.deleted ='n'     AND fieldf1 = COALESCE(@ searchf1,fieldf1)     AND fieldr1 = COALESCE(@ searchr1,fieldr1)      - 等等 ORDER BY fieldf1

通过这种方式,您不使用动态SQL并且它具有可读性,当您想要省略数据时,只需将变量设为null。

注意: 正如我所提到的,如果任何COALESCE列包含空值,则此路由将不起作用。