加入具有重复行数据的表时如何获得正确的 SUM()?

Posted

技术标签:

【中文标题】加入具有重复行数据的表时如何获得正确的 SUM()?【英文标题】:How to get correct SUM() when joining table with duplicated row data? 【发布时间】:2021-11-30 04:52:57 【问题描述】:

目前我有 3 个表,第一个表“用户”包含 iduser_name。第二个表“列表”包含refnoagent_id。我的第三个表“日志”包含refnostatus。现在我想在他们的状态旁边显示一个人的名字。所以基本上我想要日志中的状态条目计数并将它们各自的用户名放在它旁边。

为此,我必须将“日志”的refno 引用到“列表”的refno,并将“列表”的agent_id 引用到“用户”的id。为此,我使用了以下语句:

select SUM(CASE WHEN status = 'Draft' THEN 1 END) AS draft,
       SUM(CASE WHEN status = 'Publish' THEN 1 END) AS publish, 
       u.name
from logs t 
inner join listings l on t.refno = l.refno 
inner join users u on l.agent_id=u.id

但这会返回如下输出:

哪里不对,我想要的输出是这样的:

Draft Publish Name
1 1 Jason
0 1 Jam

我添加了一个带有数据的 sqlfiddle 以使参考更容易理解:http://sqlfiddle.com/#!9/22b6e4/5

【问题讨论】:

您可以将结果分组:group by l.agent_id 好的,我试过这个,它带来了第二行,但是如果你在小提琴中检查第一行数据是不正确的 您的列表中有重复列表,其值为“A123”。 是的,因为“A123”不是唯一值。该列表的状态在特定时间范围内从发布更改为草稿。 @JayVijayModi 检查我的更新答案 【参考方案1】:

更新: 根据下面的 cmets,您需要首先在 FROM 子句中创建伪表,该表必须包含所有必要的数据才能获得所需的结果。 下面的子查询创建了一个包含所有必需数据的伪表。

SELECT u.id,
       u.name,
       t.status,
       t.refno
FROM logs t 
INNER JOIN listings l ON t.refno = l.refno 
INNER JOIN users u ON l.agent_id = u.id
GROUP BY t.refno, u.name, t.status;

您只需将上述查询包装为原始查询的FROM 子句中的子查询。 因此,这是获得所需输出的最终查询。

SELECT SUM(CASE WHEN tab.status = 'Draft' THEN 1 ELSE 0 END) AS draft,
       SUM(CASE WHEN tab.status = 'Publish' THEN 1 ELSE 0 END) AS publish,
       tab.name
FROM (SELECT u.id,
      u.name,
      t.status,
      t.refno
      FROM logs t 
      INNER JOIN listings l ON t.refno = l.refno 
      INNER JOIN users u ON l.agent_id = u.id
      GROUP BY t.refno, u.name, t.status) AS tab
GROUP BY tab.name
ORDER BY tab.id;

原答案:

您需要添加一个GROUP BY 子句以根据您所需的参数对结果进行分组。 您可以在此处按l.agent_idu.id 分组。

我注意到的另一件事是,您需要在 SUM 语句中添加 ELSE 子句以返回 0,以防查询返回意外的 status。 像这样的:SUM(CASE WHEN status = 'Publish' THEN 1 ELSE 0 END)

所以你的最终查询变成了这样:

SELECT SUM(CASE WHEN status = 'Draft' THEN 1 ELSE 0 END) AS draft,
       SUM(CASE WHEN status = 'Publish' THEN 1 ELSE 0 END) AS publish, 
       u.name 
FROM logs t 
INNER JOIN listings l ON t.refno = l.refno 
INNER JOIN users u ON l.agent_id=u.id
GROUP BY u.id;

【讨论】:

嘿,所以我在我的小提琴中尝试了这个,但仍然没有给我想要的输出。注意:“A123”不是唯一值。该列表的状态在特定时间范围内从发布更改为草稿。 @JayVijayModi 如果我们谈论的是时间范围,那么我想有必要为您的架构添加时间戳 是的,在我的原始数据库中有一个带有时间戳的列,但现在为了简单起见,我已经制作了输出所有内容的小提琴,这基本上意味着完整的时间范围。有了这个输出应该是 Jason->1->1 和 Jam->0->1【参考方案2】:

要克服的一个明显问题是您的列表表格中的数据不唯一——这会扭曲您的总和。

您只需要在唯一的行上加入,这样您就不会多次计算随后加入的行。

SELECT u.id,
       u.name,
       SUM(status = 'Draft') AS draft,
       SUM(status = 'Publish') AS publish
FROM users AS u
JOIN (SELECT DISTINCT * FROM listings) AS l ON u.id = l.agent_id
JOIN logs AS t ON l.refno = t.refno
GROUP BY u.id

我更喜欢在结果集中包含 id,因为名称通常不是唯一的。

http://sqlfiddle.com/#!9/22b6e4/48

【讨论】:

你觉得其他答案比我的更好吗? @Jay 这是解决给定问题的更简洁的方法! 现在这个 sockpuppet 已经被 mods 删除了,我想改变接受的答案是没有希望的。 :(

以上是关于加入具有重复行数据的表时如何获得正确的 SUM()?的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有重复数据的情况下对两个具有连接的表进行求和?

当我加入另一个表时,SUM 不正确

连接表时H2数据库重复行

加入多个具有访问权限的表

如何以 HH:MM:SS 格式获得具有精确值的时间字段的正确 sum()

在连接两个表时获得R中的加权平均值