2010-05-09 128 views
3

我试图在SQL Server 2008数据库的表上执行查询。我有一个使用五个int参数的存储过程。目前,我的参数定义如下:SQL Server 2008中的条件WHERE子句

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

此过程将通过-1或更高的每个参数。值为-1意味着WHERE子句不应该在join /子句中考虑该参数。如果参数的值大于-1,我需要考虑我的WHERE子句中的值。我宁愿不使用IF-ELSE语句,因为这种情况似乎很sl sl。我看到这个问题here。但是,它并不适合我。我认为原因是因为我的表中的每个列都可以有一个NULL值。有人在第五个答案中指出了这种情况。这似乎正在发生在我身上。

对我的问题有没有一个流畅的方法?还是我只是需要蛮力(我希望不会:()

谢谢

回答

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) 
+0

这比使用'COALESCE'(对于NULL情况下)更快吗? – crush 2016-05-09 21:00:08

1

我建议动态SQL - 根据收到的参数生成查询作为字符串(VARCHAR)仅添加项目Ť o你真正需要的where子句。然后使用sp_executesql来运行它。动态SQL通常比预编译的SQL效率低,但在你的情况下,这听起来像是正确的路要走。请务必参数化查询,为优化程序提供重用查询计划时的最佳选择。

+0

我一直在存储过程中发现动态SQL有点奇怪。关于我曾经使用过的唯一时间是在某些公开的情况下。 – BradBrening 2010-05-09 20:33:13

+0

我通常在搜索页面等用户有许多不同的过滤选项的地方使用它。很多时候,这不是'where'子句中的一些额外'或'的简单问题 - 它还可能需要'from'子句中的附加表。在这些情况下使用动态sql可能会比试图覆盖所有基础的单个巨大查询更有效。 – Ray 2010-05-09 20:49:37

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来产生性能最好的查询。