Преобразование вложенного шаблона sql where-in в объединения - PullRequest
5 голосов
/ 26 августа 2011

У меня есть запрос, который возвращает мне правильные данные, но я не разработчик, а разработчик как.

Мой код в настоящее время

select * from adjustments where store_id in (
    select id from stores where original_id = (
        select original_id from stores where name ='abcd'))

Любые ссылки на лучшее использование объединений также приветствуются.

Ответы [ 4 ]

5 голосов
/ 26 августа 2011

Помимо любых возможных улучшений производительности, я считаю, что следующее гораздо легче читать.

SELECT  * 
FROM    adjustments a
        INNER JOIN stores s ON s.id = a.store_id
        INNER JOIN stores s2 ON s2.original_id = s.original_id
WHERE   s.name = 'abcd'        

Тестовый скрипт, показывающий мою первоначальную ошибку в пропуске original_id

DECLARE @Adjustments TABLE (store_id INTEGER)
DECLARE @Stores TABLE (id INTEGER, name VARCHAR(32), original_id INTEGER)

INSERT INTO @Adjustments VALUES (1), (2), (3)
INSERT INTO @Stores VALUES (1, 'abcd', 1), (2, '2', 1), (3, '3', 1)

/* 
   OP's Original statement returns store_id's 1, 2 & 3 
   due to original_id being all the same
*/
SELECT  * FROM @Adjustments WHERE store_id IN (
  SELECT id FROM @Stores WHERE original_id = (
    SELECT original_id FROM @Stores WHERE name ='abcd'))

/* 
   Faulty first attempt with removing original_id from the equation
   only returns store_id 1
*/
SELECT  a.store_id
FROM    @Adjustments a
        INNER JOIN @Stores s ON s.id = a.store_id
WHERE   s.name = 'abcd'        
2 голосов
/ 26 августа 2011

Если бы вы использовали объединения, это выглядело бы так:

select *
from adjustments
inner join stores on stores.id = adjustments.store_id
inner join stores as stores2 on stores2.original_id = stores.original_id
where stores2.name = 'abcd'

(очевидно, вы можете опустить второй SELECT в таблице магазинов (я оставил его в своем запросе), потому что еслиЯ правильно интерпретирую структуру вашей таблицы,
select id from stores where original_id = (select original_id from stores where name ='abcd')
совпадает с
select * from stores where name ='abcd'.)

-> отредактировал мой запрос обратно в исходную формуСпасибо Ливену за то, что он указал на мою ошибку в его ответе !

Я предпочитаю использовать объединения, но для таких простых запросов, как правило, нет разницы в производительности.SQL Server внутренне обрабатывает оба запроса.

Если вы хотите быть уверены, вы можете посмотреть план выполнения .
Если вы выполните оба запроса вместе, SQL Server также будетсказать, какой запрос потребовал больше ресурсов, чем другой (в процентах).

1 голос
/ 26 августа 2011

Как говорят Microsoft здесь :

Многие операторы Transact-SQL, которые включают подзапросы, могут быть альтернативно сформулированы как соединения. Другие вопросы могут быть заданы только с подзапросами. В Transact-SQL обычно нет производительности Разница между утверждением, которое включает в себя подзапрос и семантически эквивалентная версия, которой нет. Однако в некоторых случаях там, где необходимо проверить существование, соединение дает лучшую производительность. В противном случае вложенный запрос должен быть обработан для каждого результата внешний запрос для обеспечения устранения дубликатов. В таких случаях объединение подход даст лучшие результаты.

Ваш случай именно такой, когда Join и подзапрос дают одинаковую производительность.

Пример, когда подзапрос не может быть преобразован в «простой» JOIN:

  select Country,TR_Country.Name as Country_Translated_Name,TR_Country.Language_Code
    from Country
JOIN TR_Country ON Country.Country=Tr_Country.Country
    where country =
       (select top 1 country 
             from Northwind.dbo.Customers C 
                          join
                  Northwind.dbo.Orders O
                  on C.CustomerId = O.CustomerID
        group by country
        order by count(*)) 

Как видите, в каждой стране могут быть разные переводы имен, поэтому мы не можем просто объединять и подсчитывать записи (в этом случае в странах с большим количеством переводов будет больше записей)
Конечно, вы можете преобразовать этот пример в:

  1. СОЕДИНЕНИЕ с производной таблицей
  2. CTE

но это другая сказка-)

1 голос
/ 26 августа 2011

Немного другой подход:

select * from adjustments a where exists
(select null from stores s1, stores s2 
where a.store_id = s1.id and s1.original_id = s2.original_id and s2.name ='abcd')
...