使用嵌套的 group-by/having 子句进行复杂连接?

Posted

技术标签:

【中文标题】使用嵌套的 group-by/having 子句进行复杂连接?【英文标题】:Complex join with nested group-by/having clause? 【发布时间】:2010-10-09 09:56:40 【问题描述】:

我最终需要包含“专辑”的“导入”记录列表 每张唱片只有一首“歌曲”。

这是我现在使用的:

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" 子句非常慢。

我尝试将整个查询设为单个(无嵌套)连接,但运行了 成组/有子句的问题。我能做的最好的就是 带有欺骗性的“导入”记录列表,这是不可接受的。

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

【问题讨论】:

您会指定 RDBMS 吗? 【参考方案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
       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)

【讨论】:

【参考方案2】:

怎么样?

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

【讨论】:

这已经足够接近了。我必须添加“按 i.id,i.created_at 分组”以实现“无重复”要求(参见原始帖子)。谢谢。 是的,我错过了。没问题。【参考方案3】:
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

(您可能不需要将COUNT 包含在SELECT 列表本身中。SQL Server 不需要它,但不同的RDBMS 可能会这样做。)

【讨论】:

【参考方案4】:

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

    存在相关子查询 (gbn) 内部连接的子查询 (achinda99) 内连接所有三个表 (luke)

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

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

【讨论】:

【参考方案5】:

我试图使整个查询 单(无嵌套)连接但遇到 小组/有问题 条款。

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

据我所知,CTE 只是一个表达式,它的工作方式类似于一个虚拟视图,仅适用于单个 select 语句 - 因此您将能够执行以下操作。 我通常发现使用 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

【讨论】:

以上是关于使用嵌套的 group-by/having 子句进行复杂连接?的主要内容,如果未能解决你的问题,请参考以下文章

嵌套选择子句会降低数据库性能吗?

Rails:使用 where 子句查找深度嵌套的关联

SQL 异常在嵌套查询中使用“USING”子句?

在嵌套结构中使用 where 子句

Spring JDBC Template 无法执行 FROM 子句中包含嵌套查询的查询

聚合子查询的 FROM 子句中的项目必须引用更高级别 FROM 子句的嵌套表