SQL Server 2008中的条件WHERE子句

时间:2010-05-09 19:53:22

标签: sql sql-server

我正在尝试对SQL Server 2008数据库中的表执行查询。我有一个使用五个int参数的存储过程。目前,我的参数定义如下:

@memberType int,
@color int,
@preference int,
@groupNumber int,
@departmentNumber int

对于每个参数,此过程将被传递-1或更高。值-1表示WHERE子句不应考虑join /子句中的该参数。如果参数的值大于-1,我需要考虑WHERE子句中的值。我宁愿不使用IF-ELSE语句,因为这种情况似乎很草率。

我看到了这个问题here。但是,它对我不起作用。我认为原因是因为我表中的每个列都可以有一个NULL值。有人在第五个答案中指出了这种情况。这似乎发生在我身上。

我的问题是否有一个灵巧的方法?或者我只是需要暴力(我希望不是:()。

谢谢!

3 个答案:

答案 0 :(得分:4)

我过去做过类似的事情:

SELECT
  .....
FROM
  dbo.SOMETABLE AS T
WHERE
  (T.memberType = @memberType OR @memberType = -1)
  AND (T.color = @color OR @color = -1)
  AND (T.preference = @preference OR @preference = -1)
  AND (T.groupNumber = @groupNumber OR @groupNumber = -1)
  AND (T.departmentNumber = @departmentNumber OR @departmentNumber = -1)

但是,一般来说,我不关心的参数是NULL。然后查询变为:

SELECT
    .....
  FROM
    dbo.SOMETABLE AS T
  WHERE
    (T.memberType = @memberType OR @memberType IS NULL)
    AND (T.color = @color OR @color IS NULL)
    AND (T.preference = @preference OR @preference IS NULL)
    AND (T.groupNumber = @groupNumber OR @groupNumber IS NULL)
    AND (T.departmentNumber = @departmentNumber OR @departmentNumber IS NULL)

答案 1 :(得分:3)

我意识到线程较旧,但这里有一些额外的细节可能有助于做出适当的决定。有多种解决方案:

1)

SELECT ...
FROM ...
WHERE 
  (T.memberType = @memberType OR @memberType = -1) 
  AND (T.color = @color OR @color = -1) 
  AND (T.preference = @preference OR @preference = -1) 
  AND (T.groupNumber = @groupNumber OR @groupNumber = -1) 
  AND (T.departmentNumber = @departmentNumber OR @departmentNumber = -1)

2)

SELECT ...
FROM ...
WHERE 
    (T.memberType = @memberType OR @memberType IS NULL) 
    AND (T.color = @color OR @color IS NULL) 
    AND (T.preference = @preference OR @preference IS NULL) 
    AND (T.groupNumber = @groupNumber OR @groupNumber IS NULL) 
    AND (T.departmentNumber = @departmentNumber OR @departmentNumber IS NULL) 

3)动态生成DML并使用EXECUTE语句

4)动态生成DML并使用sp_executesql

选项1和2几乎相同......我倾向于使用IS NULL而不是-1,但与大多数事情一样,它取决于具体情况。这些选项的缺点之一是存储过程的第一次执行将产生一个查询计划,该计划将在所有后续调用中重复使用...随着参数值的变化(具体而言,您要忽略哪些),初始查询计划可能不再是最佳计划...要解决此问题,请使用WITH RECOMPILE选项(需要注意的是每次调用该程序时都会重新编译该程序)。

随着向表中添加更多数据和/或向WHERE子句添加更多条件,选项3和4的性能更佳。但是,这些选项需要更多工作来编写存储过程,并需要对输入参数进行更多验证,以最大限度地减少潜在的SQL注入漏洞。选项4优于选项3,并且在某种意义上稍微简单一些,因为动态生成的SQL包含参数名称,这会导致更有效的查询计划重用。动态生成SQL的另一个缺点是调用存储过程的用户必须具有基础表/视图的所有必要权限...除非使用WITH EXECUTE AS ...子句定义过程。

最后,我通常使用动态生成的SQL和sp_executesql来生成性能最佳的查询。

答案 2 :(得分:1)

我建议使用动态sql - 根据您收到的参数将查询生成为字符串(varchar)。仅将项添加到您真正需要的where子句中。然后使用sp_executesql运行它。动态sql通常比预编译的sql效率低,但在你的情况下,它听起来是正确的方法。请务必参数化查询,以便优化程序在重新使用查询计划时获得最佳效果。