【问题标题】:Postgres LEFT JOIN not returning nulls?Postgres LEFT JOIN 不返回空值?
【发布时间】:2020-01-24 05:25:38
【问题描述】:

不知道为什么会这样,但我有这个问题:

SELECT vote.user_id, ARRAY_AGG(COALESCE(vote.value, 0)) FROM item
LEFT JOIN vote ON item.item_id = vote.item_id
GROUP BY vote.user_id
ORDER BY user_id;

并且item表有100个元素。

我正在寻找按 user_id 分组的结果行,并且每个数组的长度为 100 个项目。也就是说,如果投票表中不存在该值,则只需将其替换为0

不幸的是,这没有发生。数组的长度不同,并且只包含现有的投票值。

我认为LEFT JOIN 会导致NULLs 代替缺失的投票值,并让COALESCE 将它们归零,但显然这不会发生。

【问题讨论】:

    标签: sql postgresql join left-join


    【解决方案1】:

    您的项目表有 100 行。你外部加入投票表。因此,您将获得所有项目投票,例如第 1 项 10 票,第 2 项 5 票,第 3 项 0 票,...如果您使用内部连接,您将失去第 3 项的 0 票,因为表中没有对第 3 项的投票。然后,每个投票都与一个用户相关。对于第 3 项没有投票,因此当您为第 3 项生成没有投票的结果时(NULL,COALESCE 变为 0),此结果为空(即用户 ID 当然也是 NULL)。这就是外连接所做的一切。

    然后您按用户分组并以数组的形式收集他们的选票。假设用户 1 有 40 票,用户 2 有 30 票,用户 3 没有票,用户 4 有 20 票。为此,您将获得三个结果行(数据中的每个用户一个):一个用于用户 1,数组包含 40 个投票,一个用于用户 2,数组包含 30 个投票,一个用于用户 4,数组包含 20投票。

    您希望每个数组神奇地包含 100 票。据此,我收集到 votes 表在用户和项目上具有唯一键,并且您希望为每个项目选择具有投票值的所有用户 - 如果没有投票条目,则为零值。

    为此,您必须首先创建所有所需的行:用户 x 项。然后外加入投票。

    SELECT u.user_id, ARRAY_AGG(COALESCE(v.value, 0) ORDER BY i.item_id)
    FROM users u
    CROSS JOIN items i
    LEFT JOIN votes v ON v.user_id = u.user_id and v.item_id = i.item_id
    GROUP BY u.user_id
    ORDER BY u.user_id;
    

    如果您想将此限制为至少拥有一票的用户,请将FROM users u 替换为FROM (SELECT DISTINCT user_id FROM votes) u 或添加HAVING COUNT(v.item_id) > 0

    【讨论】:

    • OP 没有提到users 表,但你可以用(SELECT DISTINCT user_id FROM votes) AS u 来代替
    • @Nick:正确。没有用户表的user_id 很少见,但有可能。您提到的子查询已经在我的答案中(在我的帖子末尾)。
    • 也许我在你编辑的时候错过了……无论如何,这是解决问题的方法。
    • 不客气。就在这一秒,我编辑了我的答案,将ORDER BY 添加到ARRAY_AGG。你可能想要这个。
    • 是的,我实际上只是这么想,并打算用它来回复,但你打败了我!再次感谢
    【解决方案2】:

    试试这个:

    select user_id, case when user_id  in (select user_id from vote) then ARRAY_AGG(value) 
    else ARRAY_AGG(0) end as value from item group by user_id;
    

    输出(投票表中不存在 2 和 3):

    1  {101}
    2  {0}
    3  {0}
    

    【讨论】:

    • 这似乎给了我与我原始帖子中的查询相同的结果。
    • 请指定预期的输出,将相应地更新查询。
    • 预期的输出(假设项目表有 5 个项目长),将是这样的:1, { 0, 0, 4, 2, 4 }2, { 0, 2, 0, 3, 0 }3, { 0, 1, 2, 1, 1} 等,其中第一列是 @ 987654326@,第二列是他们的投票。我的问题是它显示的值如下:1, { 4, 2, 4 }2, { 2, 3 }3, { 1, 2, 1, 1},我正在寻找不存在投票的0 值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-02
    • 2015-12-14
    • 2021-09-12
    • 2019-03-25
    相关资源
    最近更新 更多