2014-03-19 31 views
1

我创建的SQL Server 2008的存储过程中的主要查询的WHERE条款可能是要么T-SQL:决定2之间WHERE子句

WHERE (MyTable.Code = 'A') 

WHERE (MyTable.Code <> 'A') 

问题:处理这个最简单的方法是什么?有一个输入参数,告诉哪个条件使用,然后使用一个if语句使用第一个SQL语句,否则第二个?似乎不是最有效的方式。

此外,有没有办法将整个WHERE子句作为输入参数传递?

实例参数

@WHERE: "WHERE (MyTable.Code='A') 

,这样就可以做...

SELECT * FROM TABLE @WHERE 
+0

动态SQL,等于或也不是参数相同。 – Mihai

+2

这听起来像你可能会走下去的路线,文章[T-SQL中的动态搜索条件](http://www.sommarskog.se/dyn-search.html)将是最好的阅读。 –

回答

1

有一个,如果在存储过程中声明这两个查询之间的决定优于(在我看来)将where子句作为参数传递。如果您将where子句作为参数传递,那么数据库的逻辑将泄漏到上面的图层中。另外,根据你如何构建你的图层,你可以打开自己的SQL注入攻击。

它会出现,虽然他们是两个不同的查询,所以也许这将更适合作为两个存储过程,然后决定在你的调用代码中调用哪一个。

+0

其实并非如此。 SQL Server将在第一次运行时缓存存储过程的执行计划,这将导致仅适用于两个选项之一的计划 –

+0

执行计划不会相同吗?它只是在同一列上做不同的查询? –

+0

对此答案+1。 @PanagiotisKanav这两个查询将有不同的where子句,不同的查询计划和bit参数不是查询的一部分。这意味着每个查询都针对其作业进行了优化,并且该参数的值不会影响创建的查询计划。所有其他(到目前为止)构建一个合并where子句的答案最终会按照您的建议结束。 SQL Server将构建与位列值最匹配的where子句,在另一种情况下,该子句可能非常糟糕。动态SQL将工作或查询提示'选项recompile'在组合where子句。 –

3

最简单的路线是有额外的参数,将决定哪一个使用以下方式。唯一的问题是,当你开始这样做时,最终可能会导致错误的执行计划。

DECLARE @Bit BIT = 0; 

SELECT * 
FROM dbo.MyTable AS m 
WHERE (m.Code <> 'A' AND @Bit = 0) 
    OR (m.Code = 'A' AND @Bit = 1) 

为了避免错误的执行计划,您有几个不同的选项。

  • OPTION(RECOMPILE)
  • OPTION(OPTIMIZE FOR(@变量= VALUE))
  • OPTION(OPTIMIZE FOR(@VARIABLE未知))
  • 使用局部变量

你可以阅读更多关于它的地方Parameter Sniffing Problem and Possible Workarounds

在你的情况下,最简单的就是使用局部变量。

例如:

CREATE PROC dbo.GetSomeData (@pBit BIT) 
AS 
BEGIN 
    DECLARE @Bit BIT = @pBit; 

    SELECT * 
    FROM dbo.MyTable AS m 
    WHERE (m.Code <> 'A' AND @Bit = 0) 
     OR (m.Code = 'A' AND @Bit = 1) 
END 
0

可以使用动态SQL,但在这种情况下,它是没有必要的。只需使用条件WHERE子句:

CREATE PROCEDURE ... 
(@IsA bit) 
AS 

SELECT ... 
WHERE (@IsA = 1 AND MyTable.Code='A') 
    OR (@IsA = 0 AND MyTable.Code<>'A') 

有没有办法通过整个WHERE子句中作为输入参数?

哦,当然,你可以在把它作为一个字符串,但也有很多风险与这样做:

  1. 该程序可以;吨被预编译,因为你的SQL将是动态。
  2. 您增加SQL注入攻击的风险
  3. 客户端必须深入了解底层SQL的结构以提供适当的WHERE子句。
0

如果你的输入参数是一个布尔值,或任何为此事,你可以做这样的事情:

SELECT * 
FROM MyTable 
WHERE (MyTable.Code='A' AND MyParameter='Equals') 
    OR (My.Table.Code <> 'A' AND MyParementer='NotEqual') 

我用类似这样的事情在过去做到这一点。

0

我建议使用参数来决定使用哪个WHERE子句。

假设您有一个名为@WhereClauseToUse的参数。

你可能有这样的事情:

select * 
from table 
where (@WhereClauseToUse = 1 and Code = 'A') 
    or (@WhereClauseToUse = 2 and Code <> 'A') 
1

如果你正在寻找的东西快速和容易的作品,你可以使用标志(或任何条件决定WHERE子句中使用它),两者结合成一个单个WHERE子句。

WHERE (@flag = 1 AND code = 'A') OR (@flag = 0 AND code <> 'A')

在飞行更高级的SQL,您可以使用dynamic sql。在WHERE子句中

0

我使用的条件,像

-- @A = 1/true, then WHERE (MyTable.Code = 'A') 
-- @A = 0/false, then WHERE (MyTable.Code <> 'A') 
declare @A bit 

WHERE ((MyTable.Code = 'A' and @A = 1) OR (MyTable.Code <> 'A' and @A = 0))