T-SQL:决定2个WHERE子句

时间:2014-03-19 15:10:17

标签: sql sql-server tsql

我在SQL Server 2008中创建存储过程。主查询的WHERE子句可能是

WHERE (MyTable.Code = 'A')

WHERE (MyTable.Code <> 'A')

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

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

示例参数

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

这样你就可以......

SELECT * FROM TABLE @WHERE

7 个答案:

答案 0 :(得分: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)

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

  • 选项(重建)
  • 选项(OPTIMIZE FOR(@ VARIABLE = VALUE))
  • 选项(优化(@VARIABLE UNKNOWN))
  • 使用局部变量

您可以在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

答案 1 :(得分:1)

在存储过程中使用if语句来决定两个查询之间(在我看来)比将where子句作为参数传递更好。如果将where子句作为参数传递,那么数据库的逻辑就会泄漏到上面的层中。另外,根据您在上面构建图层的方式,您可以打开自己的SQL注入攻击。

虽然看起来它们是两个不同的查询,所以这可能更适合作为两个存储过程,然后在你的调用代码中决定要调用哪一个。

答案 2 :(得分:1)

如果您正在寻找快速简便的方法,可以使用标志(或任何条件决定使用哪个WHERE子句)并将它们组合成一个WHERE子句。

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

对于更高级的SQL,您可以使用dynamic sql

答案 3 :(得分: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子句。

答案 4 :(得分:0)

如果您的输入参数是布尔值,或任何相关的东西,您可以执行以下操作:

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

我过去曾使用类似的东西来实现这一目标。

答案 5 :(得分:0)

我建议使用一个参数来指示将使用哪个WHERE子句。

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

你可以这样:

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

答案 6 :(得分:0)

我在WHERE子句中使用了条件,比如

-- @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))