SQL Server - выберите другой альтернативный запрос - PullRequest
0 голосов
/ 20 июня 2011

Ранее я задавал вопрос о замене использования 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 ]

1 голос
/ 20 июня 2011

Когда вы ПРИСОЕДИНЯЕТЕСЬ, вы получаете частичное декартово произведение.Частичное происходит из условия INNER JOIN.

Таким образом, для 2 строк в EM, которые имеют 3 строки и 4 строки в PR соответственно, вы получите 7 строк в выходных данных.Как и ожидалось.Вы попросили «дать мне все частичные декартовы произведения EM и PR, где совпадают строки»

Однако вы хотите «дать мне строки в EM, где есть что-то в PR».Таким образом, INNER JOIN - неправильная конструкция.

Вы можете использовать IN, EXISTS (или INTERSECT в других ситуациях), и все они семантически правильны для этого последнего вопроса.

В этом случае вы используете IN не в том месте.Как я уже говорил, все условие «test» должно быть помещено в подзапрос.

Итак, оба они верны

  • Одна таблица в предложении 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 входов, что ближе к вашему исходному запросу:

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
0 голосов
/ 20 июня 2011

Попробуйте использовать 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)
0 голосов
/ 20 июня 2011

Нет необходимости в различном коде ниже

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
0 голосов
/ 20 июня 2011

(новый) оптимизатор запросов будет обрабатывать IN так же, как EXISTS, если вы оцениваете подзапрос.

Поскольку вы используете IN, вам не нужен DISTINCT в вашем подзапросе. Просто возьми!

Похоже, что кто-то пишет запросы и всегда использует DISTINCT, что является довольно ужасной привычкой. DISTINCT следует использовать только во избежание дублирования. Нет смысла удалять дубликаты в вашем подзапросе, так как будет точно так же сказать, что 1 находится в 1,2,1,3, как и сказать, 1 находится в 1,2,3.

0 голосов
/ 20 июня 2011

Этот запрос мне подходит. Это работает медленно? Вам действительно нужно обрезать имя и фамилию? Если нет, вы можете игнорировать их.

 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. Если вам нужны разные строки, exist () не поможет.

...