SQL Server - 选择不同的备用查询

时间:2011-06-20 18:03:17

标签: sql-server select distinct

之前我问过一个关于替换使用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

5 个答案:

答案 0 :(得分:1)

当您加入时,您将获得部分笛卡尔积。部分来自INNER JOIN条件。

因此对于EM中分别有3行和4行的2行,输出中会有7行。正如所料。你问“给我所有EM和PR的部分笛卡儿积的匹配行”

然而,你想要“给我在EM中的行,其中有PR的东西”。所以INNER JOIN是错误的构造。

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

在这种情况下,您使用IN的位置错误。正如我之前所说,整个“测试”条件应该被推入子查询。

所以,这两个都是正确的

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

停止加入!

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

答案 1 :(得分:0)

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

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

看起来有人正在编写查询并总是使用DISTINCT,这是一个非常糟糕的习惯。 DISTINCT只应用于避免重复。没有理由消除子查询中的欺骗,因为11,2,1,3中的1一样准确,因为1,2,3位于{{1}}。< / p>

答案 2 :(得分:0)

下面的代码不需要明确

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

尝试使用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)

答案 4 :(得分:-1)

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

 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()可用于在某些其他sqls执行之前将某些内容检查为条件。  如果你需要不同的行,exists()将无济于事。