SQL Server查询:SELECT 1 WHERE EXISTS与SELECT TOP 1 1 (SQL Server query: SELECT 1 WHERE EXISTS vs SELECT TOP 1 1)

3

我需要展示一个标志 - 如果条件不满足则为0,如果满足则为1 - 我可以用两种不同的方式来实现:

获取员工ID、姓名,以及是否有其他子订单的标志(有则为1,没有则为0):

SELECT e.ID
     , e.Name
     , ISNULL ( ( SELECT TOP 1 1 FROM Employee se WHERE se.ManagerID = e.ID ) , 0 ) AS HasSubordinates 
  FROM Employee e

或者

SELECT e.ID
     , e.Name
     , ISNULL ( ( SELECT 1 WHERE EXISTS ( SELECT * FROM Employee se WHERE se.ManagerID = e.ID ) ) , 0 ) AS HasSubordinates 
  FROM Employee e

你会选择哪个版本?为什么?


更新 1


这个版本怎么样?

SELECT o.ID
     , o.Name
     , o.StartDate
     , o.EndDate
     , ISNULL ( ( SELECT TOP 1 1 FROM changes c WHERE c.ChangeDate BETWEEN o.StartDate AND o.EndDate ) , 0 ) AS IsChanged
  FROM Orders o

或者

SELECT o.ID
     , o.Name
     , o.StartDate
     , o.EndDate
     , ISNULL ( ( SELECT 1 WHERE EXISTS ( SELECT * FROM changes c WHERE c.ChangeDate BETWEEN o.StartDate AND o.EndDate ) ), 0 ) AS IsChanged
  FROM Orders o

感谢__OMG Ponies__的快速回答。我会验证正确性。顺便问一下:你在Stackoverflow上花了多少时间 - 我看到你非常活跃 :) - MiniMe
2
更新将为所有行返回相同的值。更改条件会对已经提供答案的人表示不尊重。 - OMG Ponies
2个回答

8

我会选择使用以下方式:

   SELECT t.id,
          t.name,
          CASE WHEN x.managerid IS NULL THEN 0 ELSE 1 END AS HasSubordinates 
     FROM EMPLOYEE t
LEFT JOIN (SELECT DISTINCT 
                  e.managerid
             FROM EMPLOYEE e) x ON x.managerid = t.id

相关联的SELECT语句在SELECT子句中是不好的——它们不能扩展,因为它们会为每行返回的结果执行。这意味着你有的行数越多,相关联的SELECT语句将被调用的次数就会越多。


抢先一步了!那绝对是正确的方式!+1! - mjv
我在发布这个问题后,看到了另一个__OMG Ponies__的问题(http://stackoverflow.com/questions/1590208)- 为什么要用__DISTINCT__而不是__GROUP BY__? - MiniMe
@MiniMe:因为它没有使用聚合函数。GROUP BY e.managerid是等效的,并且会执行相同的操作。 - OMG Ponies

2
我不会选择这两种方法......原因是(据我所知),当在SELECT语句中有子查询时,该子查询将为返回的每一行执行一次。因此,如果主查询返回100行,则实际上运行了101个查询。当您使用JOIN时,只需执行一次需要将左侧和右侧匹配的查询即可。请注意,如果您在ManagerId上建立索引,则会有所帮助。尝试像这样做:
SELECT e.ID,
       e.Name,
       COUNT(se.ID) AS TotalStaff
FROM    Employee e 
        LEFT JOIN Employee se 
                ON se.ManagerID = e.ID
GROUP BY e.ID, e.Name 

我的回答与你之前得到的略有不同,因为我返回的是总数而不仅仅是0|1,但如果你需要1|0,这很容易更改...

请告诉我这是否有所帮助。


COUNT(se.ID) 将会遍历 LEFT JOIN 表中的所有行。我试图通过只选择符合条件的第一行 - 或者使用 EXISTS 来避免这种情况发生。 - MiniMe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接