高效的SQL查询,可从多个表中添加总计和存在总计

时间:2019-07-15 23:56:21

标签: sql aggregate-functions rdbms query-performance sqlperformance

我有两个桌子

  • 杂志,其字段为 id,名称;
  • 具有域 subscriber_id magazine_id
  • Subscriptions ,它们是 Magazines 和另一个订户表的外键。

我想将杂志表扩展为:

  • 第三列列出其 subscribers
  • 总数
  • 第四列 subscribed ,其布尔值是true,前提是当 Subscriptions 中有一条带有我的Subscriber_id的记录时(我们可以说我是 subscriber_id = 1 )。

是否有解决这些问题的规范方法?如果没有,我该如何有效地做到这一点?

要获得“订户”专栏,我想到的最简单的事情是不会列出没有订户的杂志。 (我确实读过here,但看不到它们之间的关系)

SELECT magazine_id, COUNT(*)
FROM subscriptions GROUP BY magazine_id
ORDER BY magazine_id ASC;

所以相反,我做了一些骇人听闻的事情,可能效率很低:

SELECT
 magazines.id,
 CASE WHEN NOT EXISTS(
  SELECT * FROM subscriptions WHERE magazines.id=magazine_id
 ) THEN 0
 ELSE COUNT(*) END AS subscribers
FROM
 magazines
LEFT JOIN
  subscriptions
ON
 magazines.id = subscriptions.magazine_id
GROUP BY
 magazines.id
ORDER BY
 magazines.id ASC;

对于第四列的布尔值,我得到了一个解决方案,即再次将先前的结果与订阅连接在一起,然后对subscriber_id的值为null的情况进行了研究。

我正在使用PostgreSQL。我不是学生,但我想学习如何解决这个问题,杂志/订户只是一个例子。我只知道SQL的基础。

2 个答案:

答案 0 :(得分:0)

第一件事是接受您要查询的订户数量并将其加入到杂志表中。

如此

SaveChanges

成为

SELECT id, COUNT(*) AS subscriber_count
FROM subscriptions GROUP BY magazine_id

关于添加(如果您是订户),有几种方法可以解决: 1)与上述类似,创建一个查询并将其加入杂志

SELECT mag.id, COALESCE(subs.subscriber_count, 0) AS subscribers
FROM magazines mag
LEFT JOIN (
    SELECT magazine_id, COUNT(*) AS subscriber_count 
    FROM subscriptions GROUP BY magazine_id) subs ON subs.magazine.id = mag.id
ORDER BY mag.id ASC

2)如果订阅表在magazine_id和Subscriber_id上是唯一的,则可以直接加入而无需子查询:

--Query:
SELECT DISTINCT magazine_id FROM subscriptions WHERE subscriber_id = 1

--Joined:
SELECT 
    mag.id, 
    COALESCE(subs.subscriber_count, 0) AS subscribers,
    CASE WHEN mysubs.magazine_id IS NULL THEN 0 ELSE 1 END AS my_subscription
FROM magazines mag
LEFT JOIN (
    SELECT magazine_id, COUNT(*) AS subscriber_count 
    FROM subscriptions GROUP BY magazine_id) subs ON subs.magazine_id = mag.id
LEFT JOIN (
    SELECT DISTINCT magazine_id FROM subscriptions WHERE subscriber_id = 1
    ) mysubs ON mysubs.magazine_id = mag.id
ORDER BY mag.id ASC

3)通过在布尔值上使用MAX聚合将条件添加到订阅子查询中

SELECT 
    mag.id, 
    COALESCE(subs.subscriber_count, 0) AS subscribers,
    CASE WHEN mysubs.magazine_id IS NULL THEN 0 ELSE 1 END AS my_subscription
FROM magazines mag
LEFT JOIN (
    SELECT magazine_id, COUNT(*) AS subscriber_count 
    FROM subscriptions GROUP BY magazine_id) subs ON subs.magazine_id = mag.id
LEFT JOIN subscriptions mysubs on mysubs.magazine_id = mag.id AND subscriber_id = 1
ORDER BY mag.id ASC

答案 1 :(得分:0)

如果您只想要杂志ID,可以执行以下操作:

select magazine_id, count(*) as num_subscribers,
       max(case when subscriber_id = 1 then 1 else 0 end) as my_subscriber
from subscriptions s
group by magazine_id;

也就是说,如果您只想要杂志ID,则不需要join

注意:这只会返回带有订阅者的杂志。

可以很容易地用left join进行扩展:

select m.mag, count(s.magazine_id) as num_subscribers,
       max(case when s.subscriber_id = 1 then 1 else 0 end) as my_subscriber
from magazines m left join
     subscriptions s
     on s.magazine_id = m.mag_id
group by m.mag_id;