是否可以选择子查询

时间:2018-02-15 10:00:16

标签: sql postgresql

考虑以下查询:

SELECT DISTINCT ON (ser.id) *
FROM server ser
LEFT JOIN subscription sub ON ser.id = sub.server_id
WHERE (
    COUNT(SELECT err.id FROM error err WHERE ser.id = err.id) > 0
    OR SUM(SELECT pay.amount FROM payment pay WHERE ser.id = pay.id) > 0
);

此处,将返回正在订阅并且有错误或付款的唯一服务器列表。

但是,我想要返回服务器ID,错误数量和付款总额,而不是返回所有服务器列(*)。例如,初始选择应如下所示:

SELECT DISTINCT ON (ser.id) ser.id, countErrors, sumPayments

选择ser.id是直截了当的,但如何从聚合函数中选择countErrors和sumPayments" count"和"总和" (考虑到它们是WHERE子句中的条件)?

我想象着"其中"条件看起来像这样:

    COUNT(SELECT err.id FROM error err WHERE ser.id = err.id) AS countErrors  > 0
    OR SUM(SELECT pay.amount FROM payment pay WHERE ser.id = pay.id) AS sumPayments > 0

有可能这样做吗?如果是这样,怎么能实现呢?

测试数据如下所示:

server
+----+
| id |
+----+
| 1  |
+----+
| 2  |
+----+
| 3  |
+----+
| 4  |
+----+

subscription
+----+-----------+
| id | server_id |
+----+-----------+
| 1  | 1         |
+----+-----------+
| 2  | 2         |
+----+-----------+
| 3  | 2         |
+----+-----------+
| 4  | 3         |
+----+-----------+
| 5  | 3         |
+----+-----------+

error
+----+-----------+
| id | server_id |
+----+-----------+
| 1  | 1         |
+----+-----------+
| 3  | 4         |
+----+-----------+

payment
+----+-----------+--------+
| id | server_id | amount |
+----+-----------+--------+
| 1  | 1         | 200    |
+----+-----------+--------+
| 2  | 2         | 200    |
+----+-----------+--------+
| 3  | 2         | 100    |
+----+-----------+--------+

测试数据的结果:

+-----------+-------------+-------------+
| server_id | countErrors | sumPayments |
+-----------+-------------+-------------+
| 1         | 1           | 200         |
+-----------+-------------+-------------+
| 2         | 0           | 300         |
+-----------+-------------+-------------+
  • 服务器#4没有订阅,因此应该省略。
  • 服务器#3有订阅,但没有错误或付款,因此应该省略。
  • 服务器#1和服务器#2都有订阅和付款和/或错误。

2 个答案:

答案 0 :(得分:2)

除非我遗漏了什么,否则我会按如下方式编写您的查询。在单独的真实子查询中执行错误和付款的聚合,并加入它们。此外,还有subscription表的连接,但这仅用于过滤掉没有订阅的服务器。最后,WHERE子句删除任何没有错误或付款的服务器。

SELECT
    s.id AS server_id,
    COALESCE(e.countErrors, 0) AS countErrors,
    COALESCE(p.sumPayments, 0) AS sumPayments
FROM server s
INNER JOIN
(
    SELECT DISTINCT server_id
    FROM subscription
) su
    ON s.id = su.server_id
LEFT JOIN
(
    SELECT server_id, COUNT(*) AS countErrors
    FROM error
    GROUP BY server_id
) e
    ON s.id = e.server_id
LEFT JOIN
(
    SELECT server_id, SUM(amount) AS sumPayments
    FROM payment
    GROUP BY server_id
) p
    ON s.id = p.server_id
WHERE
    p.sumPayments > 0 OR
    e.countErrors > 0
ORDER BY
    s.id;

enter image description here

Demo

答案 1 :(得分:1)

这里的错误是将COUNT放在SELECT之外,它需要进入内部:

(SELECT COUNT(err.id) FROM error err WHERE ser.id = err.id) > 0
    OR (SELECT SUM(pay.amount) FROM payment pay WHERE ser.id = pay.id) > 0
相关问题