将嵌套的sql转换为联接模式

时间:2011-08-26 07:15:45

标签: sql sql-server database join

我有一个查询正在向我返回正确的数据,但是作为开发人员而不是DBA我想知道是否有任何理由将其转换为连接而不是嵌套选择,如果是这样,它会是什么样子等。

我的代码目前是

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

任何对更好地使用连接的引用也会受到赞赏。

4 个答案:

答案 0 :(得分:5)

除了可能的性能改进之外,我发现以下内容更容易阅读。

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'        

答案 1 :(得分:2)

如果您使用连接,它将如下所示:

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'。)
- >将我的查询编辑回原始表格,感谢Lieven在his answer指出我的错误!

我更喜欢使用连接,但对于这样的简单查询,通常没有性能差异。 SQL Server在内部对这两个查询进行相同的处理。

如果您想确定,可以查看execution plan 如果同时运行两个查询,SQL Server还会告诉您哪个查询占用的资源多于另一个(百分比)。

答案 2 :(得分:1)

略有不同的方法:

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')

答案 3 :(得分:1)

正如微软here所说:

  

包含子查询的许多Transact-SQL语句都可以   或者配制成连接。其他问题只能提出   用子查询。在Transact-SQL中,通常没有性能   包含子查询和a的语句之间的区别   没有的语义等价版本。但是,在某些情况下   在必须检查存在的情况下,连接会产生更好的性能。   否则,必须为每个结果处理嵌套查询   外部查询以确保消除重复。在这种情况下,加入   方法会产生更好的结果。

您的情况恰好是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(*)) 

正如您所看到的,每个国家/地区都可以使用不同的名称翻译,因此我们无法加入和统计记录(在这种情况下,翻译量较大的国家/地区的记录数量会更多) 在cource中,您可以将此示例转换为:

  1. 使用派生表
  2. 加入
  3. CTE
  4. 但这是另一个故事 - )