当我进行两个联接时,为什么COUNT的结果加倍?

Tho*_*aud 5 sql postgresql postgresql-9.6

我有这张桌子

设备

 id      name         groupId     serviceId
791   Mamie Ortega      205         1832
Run Code Online (Sandbox Code Playgroud)

 id   serviceId
205     1832
Run Code Online (Sandbox Code Playgroud)

记录

 id          date                      deviceId
792   2017-07-13 13:30:19.740360         784
793   2017-07-13 13:30:19.742799         784
Run Code Online (Sandbox Code Playgroud)

警报

 id    status    deviceId
241      new        784
242      new        784 
Run Code Online (Sandbox Code Playgroud)

我正在运行此查询

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;
Run Code Online (Sandbox Code Playgroud)

哪个给我这个结果

 id      name       last24HMessagesCount      activeAlarmsCount   
791   Mamie Ortega         4                          4
Run Code Online (Sandbox Code Playgroud)

这个结果是错误的,我应该为last24HMessagesCount和activeAlarmsCount使用2。

如果我删除其中一项,例如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;
Run Code Online (Sandbox Code Playgroud)

结果是正确的

 id      name       activeAlarmsCount   
791   Mamie Ortega         2
Run Code Online (Sandbox Code Playgroud)

我不明白,为什么计数加倍?

Tho*_*ner 6

这个问题很容易回答。你有两个record和两个alarm。您将这些加入并得到四条记录,您可以数一下。

您可以通过计算不同的 ID 来解决此问题:

COUNT(DISTINCT records.id) AS "last24HMessagesCount",
COUNT(DISTINCT alarms.id) AS "activeAlarmsCount"
Run Code Online (Sandbox Code Playgroud)

但我不推荐这个。你为什么要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;
Run Code Online (Sandbox Code Playgroud)

(我已经删除了对“组”表的不必要的连接。)