【问题标题】:Complex join with nested group-by/having clause?使用嵌套的 group-by/having 子句进行复杂连接?
【发布时间】: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 吗?

标签: sql join group-by having


【解决方案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 更快:

      1. 存在相关子查询 (gbn)
      2. 内部连接的子查询 (achinda99)
      3. 内连接所有三个表 (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
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-08-15
          • 1970-01-01
          • 2015-11-01
          • 2016-02-05
          • 1970-01-01
          • 2011-12-16
          • 2013-09-22
          相关资源
          最近更新 更多