重构选择位置和/或存在

时间:2019-07-18 15:15:39

标签: sql sql-server

SELECT *
FROM a
WHERE
    a.field = @fieldValue
    AND (YEAR(a.myDate) = @y
         OR EXISTS (SELECT *
                    FROM b
                    WHERE b.Id = a.Id)
         OR EXISTS (SELECT *
                    FROM c
                    WHERE c.Id = a.Id)
        )

如何用更简单的方式重写它?

3 个答案:

答案 0 :(得分:1)

我个人认为您的查询没有任何问题,EXISTS似乎是这里的最佳选择,因为JOIN可以创建重复的行(正如我在下面的注释中显示的那样)您的答案之一)。正如我在评论中提到的,我实际上将扩展查询以在日期列上使用SARGable WHERE子句:

DECLARE @fieldValue varchar(10) = 'SomeValue',
        @y int = 2019;

DECLARE @StartDate date = CONCAT(@y,'0101'),
        @EndDate date = CONCAT(@y+1,'0101');

SELECT a.* --This should be expanded if using a persisted object
FROM a
WHERE a.field = @fieldValue
  AND (a.myDate >= @StartDate AND a.MyDate < @EndDate
    OR EXISTS (SELECT 1 FROM b WHERE b.Id = a.Id)
    OR EXISTS (SELECT 1 FROM c WHERE c.Id = a.Id));

答案 1 :(得分:-1)

使用cte的解决方案:

WITH bb AS (
    SELECT b.Id
    FROM b
    JOIN a ON b.Id=a.Id
    GROUP BY b.Id
),
WITH cc AS (
    SELECT c.Id
    FROM c
    JOIN a ON c.Id=a.Id
    GROUP BY c.Id
)
SELECT *
FROM a
LEFT JOIN bb ON a.Id=bb.Id
LEFT JOIN cc ON a.Id=cc.Id
WHERE
a.field=@fieldValue AND (YEAR(a.myDate)=@y OR bb.Id IS NOT NULL OR cc.Id IS NOT NULL)

答案 2 :(得分:-2)

SELECT *
FROM a
LEFT JOIN b ON a.Id=b.Id
LEFT JOIN c ON a.Id=c.Id
WHERE a.field=@fieldValue AND (YEAR(a.myDate)=@y OR b.Id IS NOT NULL OR c.Id IS NOT NULL)

等效且可读性更高(更简单)