带有嵌套 group-by/having 子句的复杂连接?

发布于 2024-07-13 21:27:37 字数 452 浏览 6 评论 0原文

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

这就是我现在使用的:

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 条款的问题。 我能做的最好的就是 带有欺骗行为的“导入”记录列表,这是不可接受的。

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

I ultimately need a list of "import" records that include "album"
records which only have one "song" each.

This is what I'm using now:

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

The nested select (with the join) is blazing fast, but the external
"in" clause is excruciatingly slow.

I tried to make the entire query a single (no nesting) join but ran
into problems with the group/having clauses. The best I could do was
a list of "import" records with dupes, which is not acceptable.

Is there a more elegant way to compose this query?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

迷爱 2024-07-20 21:27:37

这个怎么样?

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 的速度要快。

How's this?

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; 

In most database systems, the JOIN works a lost faster than doing a WHERE ... IN.

生生漫 2024-07-20 21:27:37
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 列表本身中包含 COUNT。SQL Server 不需要它,但不同的 RDBMS 可能需要它。)

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

(You might not need to include the COUNT in the SELECT list itself. SQL Server doesn't require it, but it's possible that a different RDBMS might.)

被翻牌 2024-07-20 21:27:37

未经测试:

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)

Untested:

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)
狼性发作 2024-07-20 21:27:37

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

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

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

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

All three sugested techniques should be faster than your WHERE IN:

  1. Exists with a related subquery (gbn)
  2. Subquery that is inner joined (achinda99)
  3. Inner Joining all three tables (luke)

(All should work, too ..., so +1 for all of them. Please let us know if one of them does not work!)

Which one actually turns out to be the fastest, depends on your data and the execution plan. But an interesting example of different ways for expressing the same thing in SQL.

听风吹 2024-07-20 21:27:37

我试图将整个查询变成
单个(无嵌套)连接但遇到
团体的问题/有
条款。

如果您使用的是 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

I tried to make the entire query a
single (no nesting) join but ran into
problems with the group/having
clauses.

You can join subquery using CTE (Common Table Expression) if you are using SQL Server version 2005/2008

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文