【问题标题】:SQL Server - Select Distinct Alternative QuerySQL Server - 选择不同的替代查询
【发布时间】:2011-09-18 21:59:53
【问题描述】:

我之前问过一个关于替代使用 SELECT DISTINCT 的问题,因为查询需要更长的时间来执行。建议我使用 EXISTS,它的效果要好得多(0 秒执行与之前的 44 秒执行相比。我对查询语法不太熟悉,但正在学习。我希望有人能够在不使用的情况下改写以下查询DISTINCT,最好使用 EXISTS(因为它以前工作得很好)。感谢任何帮助。

select distinct EM.Employee, 
                rtrim(EM.FirstName) + ' ' + rtrim(EM.LastName) as Name 
from EM EM 
inner join PR PR 
    on EM.Employee = PR.ProjMgr 
where PR.WTS1 in (Select distinct WTS1 
                  from TabFields 
                  where custInclude = 'Y' and WTS2 = '') 
    and PR.WTS2 = '' 
order by Name

【问题讨论】:

  • 您应该尝试理解上一个问题的答案并将其应用到这个问题上。如果您只是将论坛中的答案复制粘贴到您的代码中而不试图理解,那么您正在朝着成为代码猴子的方向走下坡路......
  • +100000000000000000 致 Remus 指出了解你在做什么更重要。
  • 这是同一个查询,但您之前的查询已经过清理了吗?仅供参考:stackoverflow.com/q/6414550/27535
  • 这是在同一个数据库上使用的另一个查询。我试了一下你的查询,gbn,它在 0 秒内完美运行。我希望将相同的结构应用于上述查询,但遇到了一些问题。

标签: sql-server select distinct


【解决方案1】:

尝试使用 GROUP BY 而不是选择 DISTINCT。您还可以将子查询从 WHERE 子句中移出,并将其用作连接中的派生表。

SELECT EM.Employee, 
       RTRIM(EM.FirstName) + ' ' + RTRIM(EM.LastName) AS Name 
FROM EM EM 
INNER JOIN PR PR 
    ON EM.Employee = PR.ProjMgr 
INNER JOIN (SELECT WTS1 
              FROM TabFields 
             WHERE custInclude = 'Y' AND WTS2 = ''
             GROUP BY WTS1) x
    ON PR.WTS1 = x.WTS1
    AND PR.WTS2 = '' 
GROUP BY EM.Employee,    RTRIM(EM.FirstName) + ' ' + RTRIM(EM.LastName) 
ORDER BY RTRIM(EM.FirstName) + ' ' + RTRIM(EM.LastName)

【讨论】:

    【解决方案2】:

    下面的代码不需要 distinct

    select  EM.Employee, 
                    rtrim(EM.FirstName) + ' ' + rtrim(EM.LastName) as Name 
    from EM 
    inner join PR 
        on EM.Employee = PR.ProjMgr 
    where exists (Select * 
                      from TabFields 
                      where custInclude = 'Y' and WTS2 = '' and PR.WTS1 = tabfields.WTS1 ) 
        and PR.WTS2 = '' -- Comment: Check if this clause is covered by the subquery and can be ommited
    order by Name
    

    【讨论】:

      【解决方案3】:

      当您加入时,您会得到一个部分笛卡尔积。部分来自 INNER JOIN 条件。

      因此,对于 EM 中的 2 行,PR 中分别有 3 行和 4 行,您将在输出中得到 7 行。正如预期的那样。你问“给我所有匹配行的 EM 和 PR 的部分笛卡尔积”

      但是,您希望“在 EM 中给我行 PR 中有某些内容”。所以 INNER JOIN 是错误的构造。

      您可以使用 IN、EXISTS(或在其他情况下使用 INTERSECT),对于后一个问题,它们在语义上都是正确的。

      在这种情况下,您对 IN 的使用是错误的。正如我之前所说,应该将整个“测试”条件推送到子查询中。

      所以,这两个都是正确的

      • FROM 子句中的一个表
      • 子查询中的所有条件
      • 没有区别

      停止加入!

      select
          EM.Employee, rtrim(EM.FirstName) + ' ' + rtrim(EM.LastName) as Name 
      from
          EM EM 
      WHERE
         EXISTS (SELECT *
             FROM
                PR PR 
                JOIN
                TabFields TF ON PR.WTS1 = TF.WTS1
             WHERE
                PR.WTS2 = '' AND
                TF.custInclude = 'Y' and TF.WBT2 = '' AND
                EM.Employee = PR.ProjMgr
                )
      
      select
          EM.Employee, rtrim(EM.FirstName) + ' ' + rtrim(EM.LastName) as Name 
      from
          EM EM 
      WHERE
         EM.Employee IN (SELECT PR.ProjMgr
             FROM
                PR PR 
                JOIN
                TabFields TF ON PR.WTS1 = TF.WTS1
             WHERE
                PR.WTS2 = '' AND
                TF.custInclude = 'Y' and TF.WBT2 = ''
             )
      

      使用更接近原始查询的 2 个 IN:

      select EM.Employee, 
                      rtrim(EM.FirstName) + ' ' + rtrim(EM.LastName) as Name 
      from EM EM 
      WHERE 
            EM.Employee IN (SELECT PR.ProjMgr
                FROM 
                  PR PR 
                where PR.WTS1 in (Select distinct WTS1 
                        from TabFields 
                        where custInclude = 'Y' and WTS2 = '') 
                  and PR.WTS2 = ''
             ) 
      order by Name
      

      【讨论】:

      • 谢谢。我没有编写原始查询,并且正在修改其他人创建的现有查询。我真的很感谢你的帮助。再次感谢。
      【解决方案4】:

      这个查询对我来说似乎很好。是否运行缓慢? 你真的需要修剪名字和姓氏吗?如果没有,您可以忽略它们。

       select distinct E.Employee, rtrim(E.FirstName) + ' ' + rtrim(E.LastName) as Name 
       from EM E join PR P on E.Employee = P.ProjMgr 
       where P.WTS1 in (Select WTS1 from TabFields where custInclude = 'Y' and WTS2 = '') 
         and P.WTS2 = '' 
       order by Name
      

      Exists() 可用于在执行其他一些 sql 之前检查某些内容作为条件。 如果您需要不同的行,exists() 将无济于事。

      【讨论】:

      • 是的,它运行缓慢,所以我一直在尝试优化它。上面的第一个查询需要 37 秒才能执行。
      • EM 表有多少行?第二个需要多长时间?两个查询是相同的,除了第二个使用连接而不是子查询。
      • 第二个在 0 秒内执行,但当我只希望返回 33 行时返回 143 行。您编写的第一个示例也返回 33。
      • 正如 JNK 所指出的,不需要在内部子查询上有一个 distinct。这可能会使它快一点。你现在可以试试吗?
      • 我尝试在没有 DISTINCT 的情况下运行,但它会拉起数千行,因为它会拉取重复项。不幸的是,对于这种情况,我要求它只提取唯一值。
      【解决方案5】:

      如果您正在评估子查询,(新)查询优化器会将INEXISTS 视为相同。

      由于您使用的是IN,因此您的子查询中不需要DISTINCT。把它拿出来!

      看起来有人在写查询并且总是使用DISTINCT,这是一个非常糟糕的习惯。 DISTINCT 只能用于避免重复。没有理由消除子查询中的欺骗,因为说11,2,1,3 中与说11,2,3 中一样准确。

      【讨论】:

        猜你喜欢
        • 2017-01-21
        • 1970-01-01
        • 1970-01-01
        • 2011-02-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-22
        • 2015-11-04
        相关资源
        最近更新 更多