2009-02-23 70 views
1

我最终需要一个包含“专辑” 记录的“导入”记录列表,每个记录只有一首“歌曲”。使用嵌套group by/having子句进行复杂连接?

这是我现在使用什么:

select i.id, i.created_at 
from imports i 
where i.id in (
    select a.import_id 
    from albums a inner join songs s on a.id = s.album_id 
    group by a.id having 1 = count(s.id) 
); 

嵌套选择(与连接)的速度极快,但外部 “在”条款是速度奇慢。

我试图让整个查询成为单个(无嵌套)连接,但运行 时出现了group/having子句的问题。我能做的最好的事情是 带有模糊的“导入”记录列表,这是不可接受的。

是否有更优雅的方式来组成这个查询?

+0

你会指定RDBMS吗? – Sung 2009-02-23 21:14:31

回答

7

这个怎么样?

SELECT i.id, 
     i.created_at 
FROM imports i 
     INNER JOIN (SELECT a.import_id 
        FROM  albums a 
          INNER JOIN songs s 
           ON a.id = s.album_id 
        GROUP BY a.id 
        HAVING Count(*) = 1) AS TEMP 
     ON i.id = TEMP.import_id; 

在大多数数据库系统中,JOIN的工作速度比执行WHERE ... IN要快。

+0

这已经够接近了。我不得不添加“通过i.id,i.created_at组”来达到“不受骗”的要求(见原文)。谢谢。 – 2009-02-23 22:29:59

2

未经测试:

select 
    i.id, i.created_at 
from 
    imports i 
where 
    exists (select * 
     from 
      albums a 
      join 
      songs s on a.id = s.album_id 
     where 
      a.import_id = i.id 
     group by 
      a.id 
     having 
      count(*) = 1) 

OR

select 
    i.id, i.created_at 
from 
    imports i 
where 
    exists (select * 
     from 
      albums a 
      join 
      songs s on a.id = s.album_id 
     group by 
      a.import_id, a.id 
     having 
      count(*) = 1 AND a.import_id = i.id) 
4
SELECT i.id, i.created_at, COUNT(s.album_id) 
FROM imports AS i 
    INNER JOIN albums AS a 
     ON i.id = a.import_id 
    INNER JOIN songs AS s 
     ON a.id = s.album_id 
GROUP BY i.id, i.created_at 
HAVING COUNT(s.album_id) = 1 

(您可能不需要包括在SELECT列表本身。SQL Server不需要它COUNT,但它可能是一个不同的RDBMS的威力。)

1

所有这三个sugested技术应该比你的WHERE更快:

  1. 存在具有相关子查询(GBN)
  2. 子查询是内加入(achinda99)
  3. 内侧连接所有三个表(路)

(所有应该工作,太......,所以+1为所有这些。请让我们知道,如果其中一个不工作!)

哪一个实际上是最快的,取决于您的数据和执行计划。但是用SQL表达同样的东西的一个有趣的例子。

1

我试图让整个查询 单(不嵌套)加入,但跑进 问题跟团/有 条款。

你可以,如果你使用的是SQL Server版本2005/2008

据我所知使用CTE(公共表表达式)加入子查询,CTE很简单,就像一个可行的虚拟视图表达只有一个选择声明 - 所以你将能够做到以下几点。 我通常使用CTE来提高查询性能。

with AlbumSongs as (
    select a.import_id 
    from albums a inner join songs s on a.id = s.album_id 
    group by a.id 
    having 1 = count(s.id) 
) 
select i.id, i.created_at 
from imports i 
     inner join AlbumSongs A on A.import_id = i.import_id