1

我最终需要一个“导入”记录列表,其中包括每个只有一首“歌曲”的“专辑”记录。

这就是我现在正在使用的:

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

嵌套选择(带有连接)非常快,但外部“in”子句非常慢。

我试图使整个查询成为单个(无嵌套)连接,但遇到了 group/having 子句的问题。我能做的最好的就是列出带有欺骗性的“导入”记录,这是不可接受的。

有没有更优雅的方式来编写这个查询?

4

5 回答 5

8

这个怎么样?

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 快。

于 2009-02-23T20:44:04.440 回答
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

(您可能不需要将 包括COUNTSELECT列表本身中。SQL Server 不需要它,但不同的 RDBMS 可能会。)

于 2009-02-23T20:45:17.293 回答
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)

或者

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)
于 2009-02-23T20:27:05.573 回答
1

所有三种建议的技术都应该比您的 WHERE IN 更快:

  1. 存在相关子查询 (gbn)
  2. 内部连接的子查询 (achinda99)
  3. 内连接所有三个表(卢克)

(所有这些都应该工作......,所以对所有这些都+1。如果其中一个不起作用,请告诉我们!)

哪个实际上是最快的,取决于您的数据和执行计划。但是一个有趣的例子是在 SQL 中表达同一事物的不同方式。

于 2009-02-23T21:06:34.230 回答
1

我试图使整个查询成为单个(无嵌套)连接,但遇到了 group/having 子句的问题。

如果您使用的是 SQL Server 版本 2005/2008,则可以使用 CTE(公用表表达式)加入子查询

As far as I know, CTE is simply an expression that works like a virtual view that works only one a single select statement - So you will be able to do the following. I usually find using CTE to improve query performance as well.

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
于 2009-02-23T21:15:40.403 回答