执行相同的查询两次,但使用单个不同的WHERE子句

时间:2014-05-31 04:44:19

标签: sql sql-server

请原谅我的问题的简单性,我有一个脑屁:

这是我的表架构:

Foo( FooId, BarDate dateTime, Baz int )

鉴于此查询

SELECT
    MAX( Foo.BarData )
FROM
    Foo
WHERE
    Foo.Baz = 2
    AND
    Foo.BarData < @dateParameter

在某些情况下,此查询返回NULL,因为没有符合条件的行,在这些情况下,我希望查询返回相同的值,Foo.Baz = 0除外。

我可以使用两个子查询来完成它,但它似乎是一个黑客。是不是有更好的方法?

SELECT
    COALESCE( Attempt1.BarData, Attempt2.BarData )
FROM
    (
        SELECT
            MAX( Foo.BarData ) As BarData
        FROM
            Foo
        WHERE
            Foo.Baz = 2
            AND
            Foo.BarData < @dateParameter
    ) As Attempt1
    OUTER JOIN
    (
        SELECT
            MAX( Foo.BarData ) As BarData
        FROM
            Foo
        WHERE
            Foo.Baz = 0
            AND
            Foo.BarData < @dateParameter
    ) As Attempt2 ON 1 = 1

4 个答案:

答案 0 :(得分:6)

只需选择两行并将结果限制为1行,订购首选行为

SELECT TOP 1
  MAX( Foo.BarData )
FROM
  Foo
WHERE
  ((Foo.Baz = 2) OR
  (Foo.Baz = 0))
AND
  Foo.BarData < @dateParameter
GROUP BY Foo.Baz
ORDER BY Foo.Baz DESC

答案 1 :(得分:4)

可以在同一查询中获取两个Foo.Baz的MAX值,使用CASE分隔原始数据

SELECT COALESCE(MAX(CASE WHEN Foo.Baz = 2 THEN Foo.BarDate ELSE NULL END)
              , MAX(CASE WHEN Foo.Baz = 0 THEN Foo.BarDate ELSE NULL END)
               )
FROM   Foo
WHERE  Foo.Baz IN (0,2)
  AND  Foo.BarDate < @dateParameter

答案 2 :(得分:1)

SELECT COALESCE(    
    (SELECT MAX(Foo.BarData) FROM Foo WHERE Foo.Baz = 2 AND Foo.BarData < @dateParameter),
    (SELECT MAX(Foo.BarData) FROM Foo WHERE Foo.Baz = 0 AND Foo.BarData < @dateParameter)
)

根据您的平台,这可能比其他答案有更好的计划。在SQL Server上,您不需要FROM子句。在Oracle上,您可以从DUAL中进行选择。其他系统可能需要一个返回单行的虚拟表达式。

OP的查询可能刚刚用交叉连接而不是外连接编写。这可能是它感觉像黑客的部分原因。我说你的要求并不是一个普通的sql-esque问题,所以任何答案都会这样。

如果你想强调典型的路径是Foo.Baz = 2,你可能会喜欢它的样子:

SELECT COALESCE(
    MAX(Foo.BarData),
    (SELECT MAX(Foo.BarData) FROM Foo WHERE Foo.Baz = 0 AND Foo.BarData < @dateParameter)
)
FROM Foo
WHERE Foo.Baz = 2 AND Foo.BarData < @dateParameter)

答案 3 :(得分:0)

只是为了完成列表,您也可以使用IF..ELSE,如下所示。

IF EXISTS (SELECT 1 FROM Foo WHERE Foo.Baz = 2)
BEGIN
SELECT  MAX( Foo.BarData)
FROM    Foo
WHERE   Foo.Baz = 2
AND     Foo.BarData < @dateParameter
END
ELSE
BEGIN
SELECT  MAX( Foo.BarData)
FROM    Foo
WHERE   Foo.Baz = 0
AND     Foo.BarData < @dateParameter
END

如果它对你有所帮助。