【问题标题】:SQL Statement JOIN only returns elements with associationSQL 语句 JOIN 只返回有关联的元素
【发布时间】:2019-10-08 22:56:47
【问题描述】:

我有在 PostgreSQL 数据库中按成员资格加入组的用户的行为。

我有一个查询来为排行榜生成行。但是,它目前排除了 Acts 表不包含具有相应 users_id 的行的用户。我想包括所有小组成员,即使是那些 0 Acts 的成员。

当前查询:

SELECT acts.users_id, username, avatar_url, COUNT(acts.id) 
FROM acts 
JOIN users ON acts.users_id = users.id 
JOIN memberships on memberships.users_id = users.id 
WHERE memberships.groups_id = ' + req.params.group_id + ' 
AND acts.created_at >= (CURRENT_DATE - 6) 
GROUP BY acts.users_id, username, avatar_url 
ORDER BY COUNT(acts.id) DESC

我尝试将用户之前的JOIN 更改为RIGHT JOINLEFT JOIN,但我得到了相同的结果。在某一时刻,我认为RIGHT JOIN 工作正常,但不知何故,我出错了。

【问题讨论】:

  • avatar_url 来自哪里?你到底要数什么?

标签: sql postgresql left-join aggregate


【解决方案1】:

我想包括所有小组成员,即使是那些 0 Acts 的成员。

跳线:

  1. 如果要包含 0 行为的成员,则不能返回 acts.users_id。请改用memberships.users_id
  2. WHERE 子句中的条件a.created_at >= (CURRENT_DATE - 6) 将使所有使用LEFT JOIN 的尝试无效。将该条件移动到JOIN 子句中。看:
SELECT m.users_id  -- !!!
     , u.username, avatar_url
     , COUNT(a.users_id) AS ct_acts
FROM   memberships m
JOIN   users       u ON m.users_id = u.id 
LEFT   JOIN acts   a ON a.users_id = u.id 
                    AND a.created_at >= (CURRENT_DATE - 6)  -- !!!
WHERE  m.groups_id = ' + req.params.group_id + '
GROUP  BY 1, 2, 3
ORDER  BY COUNT(*) DESC;

假设membershipsusers 之间的引用完整性(FK 约束),因此与用户的连接可以保持为[INNER] JOIN

还假设 "all group members" 是指所有WHERE m.groups_id = ' + req.params.group_id + ',否则我们需要做更多。

但是你到底在数什么?目前,这看起来像是具有组成员身份的行为的乘法。可能是误会。见:

根据确切的表定义和您想要计算的内容,可能会有更快的查询...

【讨论】:

  • 感谢欧文。你说的一切都是正确的。删除 CURRENT_DATE 约束会导致排行榜呈现,但显然,日期约束很重要。我不得不调整上面的查询以替换 GROUP BY 子句中的 m.users_id 而不是 a.users_id,但它工作得很好
  • 欧文,我现在很好奇更快查询的可能性。澄清一下,排行榜根据用户在过去 7 天内完成的行为数量对组中的用户进行排名。有没有更高效的查询?再次感谢!
  • @user2799827:就像我说的:取决于确切的表定义。请开始一个新问题,披露相关信息:Postgres 版本,CREATE TABLE 语句,相关列显示数据类型和约束。我有根据的猜测:有一种更快的方法。您可以随时链接到此问题/答案以获取上下文。
【解决方案2】:

我以前也遇到过这样的问题。我要做的是删除所有 where 语句和连接。首先将 users 加入到 acts,然后查看查询是否保留了您想要的非活动用户。同样尝试在 usersmemberships 之间进行左连接。一旦您查询了两个表,其中的用户在 ACT 表中不存在。将第三个表与前两个表的输出连接起来。然后最后应用你的 where 语句并按计数分组。

【讨论】:

    【解决方案3】:

    如果要返回没有acts的用户,需要从acts以外的其他表开始。 例如,您可以尝试从用户表而不是行为开始:

    SELECT acts.users_id, username, avatar_url, COUNT(acts.id) 
    FROM users
    LEFT JOIN acts ON acts.users_id = users.id 
    LEFT JOIN memberships on memberships.users_id = users.id 
    WHERE memberships.groups_id = ' + req.params.group_id + ' 
    AND acts.created_at >= (CURRENT_DATE - 6) 
    GROUP BY acts.users_id, username, avatar_url 
    ORDER BY COUNT(acts.id) DESC
    

    这应该返回所有用户,即使他们没有行为或会员资格。

    【讨论】:

    • 我已经完全复制了这个,我得到了相同的结果。也许它是 Express 或 Vue 中的东西?
    • 我已经从内部到左再返回,结果数组每次都是一样的,这让我觉得有问题。我每次都在重启api服务器。
    猜你喜欢
    • 2016-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多