为什么当我做两个连接时 COUNT 的结果是双倍的?
Why are the result of COUNT double when I do two join?
我有这张桌子
设备
id name groupId serviceId
791 Mamie Ortega 205 1832
组
id serviceId
205 1832
记录
id date deviceId
792 2017-07-13 13:30:19.740360 784
793 2017-07-13 13:30:19.742799 784
警报
id status deviceId
241 new 784
242 new 784
我运行这个查询
SELECT device.id, device.name, COUNT(records.id) AS "last24HMessagesCount", COUNT(alarms.id) AS "activeAlarmsCount"
FROM device
INNER JOIN "group" AS "group" ON "device"."groupId" = "group"."id" AND "group"."id" = '205'
LEFT OUTER JOIN "record" AS "records" ON "device"."id" = "records"."deviceId" AND "records"."date" > '2017-07-12 11:43:02.838 +00:00'
LEFT OUTER JOIN "alarm" AS "alarms" ON "device"."id" = "alarms"."deviceId" AND "alarms"."status" = 'new'
WHERE "device"."serviceId" = 1832
GROUP BY device.id;
哪个给我这个结果
id name last24HMessagesCount activeAlarmsCount
791 Mamie Ortega 4 4
这个结果是错误的,我应该有 2 个 last24HMessagesCount 和 activeAlarmsCount。
如果我删除其中一个计数,例如 last24HMessagesCount 并执行
SELECT device.id, device.name, COUNT(alarms.id) AS "activeAlarmsCount"
FROM device
INNER JOIN "group" AS "group" ON "device"."groupId" = "group"."id" AND "group"."id" = '205'
LEFT OUTER JOIN "alarm" AS "alarms" ON "device"."id" = "alarms"."deviceId" AND "alarms"."status" = 'new'
WHERE "device"."serviceId" = 1832
GROUP BY device.id;
结果正确
id name activeAlarmsCount
791 Mamie Ortega 2
我不明白,为什么计数是双倍的?
您的联接正在沿两个维度生成笛卡尔积。最简单的解决方案是使用 COUNT(DISTINCT)
:
SELECT device.id, device.name,
COUNT(DISTINCT records.id) AS "last24HMessagesCount",
COUNT(DISTINCT alarms.id) AS "activeAlarmsCount"
如果计数不是很大,这会起作用。替代解决方案更具可扩展性。那就是在 之前 LEFT JOIN
或使用相关子查询(或横向连接)进行聚合。
这个回答起来很简单。你有两个 record
和两个 alarm
。你加入这些并获得四条记录,你数一数。
您可以通过计算不同的 ID 来解决此问题:
COUNT(DISTINCT records.id) AS "last24HMessagesCount",
COUNT(DISTINCT alarms.id) AS "activeAlarmsCount"
但我不推荐这个。你为什么要加入 record
和 alarm
?它们没有直接关系。你想加入的是record
的人数和alarm
的人数。所以在加入之前聚合:
SELECT
device.id,
device.name,
records.cnt AS "last24HMessagesCount",
alarms.cnt AS "activeAlarmsCount"
FROM device
LEFT OUTER JOIN
(
SELECT deviceId, count(*) AS cnt
FROM record
WHERE "date" > '2017-07-12 11:43:02.838 +00:00'
GROUP BY deviceId
) AS records ON device.id = records.deviceId
LEFT OUTER JOIN
(
SELECT deviceId, count(*) AS cnt
FROM alarm
WHERE status = 'new'
GROUP BY deviceId
) AS alarms ON device.id = alarms.deviceId
WHERE device.serviceId = 1832
AND device.groupId = 205;
(我删除了 "group" table 中不必要的连接。)
我有这张桌子
设备
id name groupId serviceId
791 Mamie Ortega 205 1832
组
id serviceId
205 1832
记录
id date deviceId
792 2017-07-13 13:30:19.740360 784
793 2017-07-13 13:30:19.742799 784
警报
id status deviceId
241 new 784
242 new 784
我运行这个查询
SELECT device.id, device.name, COUNT(records.id) AS "last24HMessagesCount", COUNT(alarms.id) AS "activeAlarmsCount"
FROM device
INNER JOIN "group" AS "group" ON "device"."groupId" = "group"."id" AND "group"."id" = '205'
LEFT OUTER JOIN "record" AS "records" ON "device"."id" = "records"."deviceId" AND "records"."date" > '2017-07-12 11:43:02.838 +00:00'
LEFT OUTER JOIN "alarm" AS "alarms" ON "device"."id" = "alarms"."deviceId" AND "alarms"."status" = 'new'
WHERE "device"."serviceId" = 1832
GROUP BY device.id;
哪个给我这个结果
id name last24HMessagesCount activeAlarmsCount
791 Mamie Ortega 4 4
这个结果是错误的,我应该有 2 个 last24HMessagesCount 和 activeAlarmsCount。
如果我删除其中一个计数,例如 last24HMessagesCount 并执行
SELECT device.id, device.name, COUNT(alarms.id) AS "activeAlarmsCount"
FROM device
INNER JOIN "group" AS "group" ON "device"."groupId" = "group"."id" AND "group"."id" = '205'
LEFT OUTER JOIN "alarm" AS "alarms" ON "device"."id" = "alarms"."deviceId" AND "alarms"."status" = 'new'
WHERE "device"."serviceId" = 1832
GROUP BY device.id;
结果正确
id name activeAlarmsCount
791 Mamie Ortega 2
我不明白,为什么计数是双倍的?
您的联接正在沿两个维度生成笛卡尔积。最简单的解决方案是使用 COUNT(DISTINCT)
:
SELECT device.id, device.name,
COUNT(DISTINCT records.id) AS "last24HMessagesCount",
COUNT(DISTINCT alarms.id) AS "activeAlarmsCount"
如果计数不是很大,这会起作用。替代解决方案更具可扩展性。那就是在 之前 LEFT JOIN
或使用相关子查询(或横向连接)进行聚合。
这个回答起来很简单。你有两个 record
和两个 alarm
。你加入这些并获得四条记录,你数一数。
您可以通过计算不同的 ID 来解决此问题:
COUNT(DISTINCT records.id) AS "last24HMessagesCount",
COUNT(DISTINCT alarms.id) AS "activeAlarmsCount"
但我不推荐这个。你为什么要加入 record
和 alarm
?它们没有直接关系。你想加入的是record
的人数和alarm
的人数。所以在加入之前聚合:
SELECT
device.id,
device.name,
records.cnt AS "last24HMessagesCount",
alarms.cnt AS "activeAlarmsCount"
FROM device
LEFT OUTER JOIN
(
SELECT deviceId, count(*) AS cnt
FROM record
WHERE "date" > '2017-07-12 11:43:02.838 +00:00'
GROUP BY deviceId
) AS records ON device.id = records.deviceId
LEFT OUTER JOIN
(
SELECT deviceId, count(*) AS cnt
FROM alarm
WHERE status = 'new'
GROUP BY deviceId
) AS alarms ON device.id = alarms.deviceId
WHERE device.serviceId = 1832
AND device.groupId = 205;
(我删除了 "group" table 中不必要的连接。)