使用postgres中的json数组在同一个表上进行多个可选连接

问题描述

我有两张桌子用户房间。我正在尝试加入两个表并获取与房间相关的用户名列表。只有当两列都有值时,我才会得到结果。如果任何一列为空,则不会给出非空列的值。请在下面找到详细信息。

用户架构:

id  name
---------
1   X
3   Y
4   Z

房间架构:

id  active_users    inactive_users
-----------------------------------
101     [1]         [3]
102     [3]         null
103     null        [4]

尝试查询

SELECT
    r.id,json_agg(u.name) as active_users,json_agg(u1.name) as inactive_users
FROM rooms r,json_array_elements(active_users) as elems
LEFT OUTER JOIN users u 
    ON u.id = elems::TEXT::INT,json_array_elements(inactive_users) as elems1
LEFT OUTER JOIN users u1 ON 
    u1.id = elems1::TEXT::INT 
GROUP BY r.id

查询输出

id  active_users    inactive_users
----------------------------------
101     ["X"]       ["Y"]

预期输出

id  active_users    inactive_users
----------------------------------
101     ["X"]       ["Y"]
102     ["Y"]       NULL
103     NULL        ["Z"]

解决方法

您在这里的主要问题是您正在与 json_array_elements(active_users) 函数进行内部联接,当 active_users 为 null 时,该函数会产生 null。因此,该连接不包括您要包含的那些行。如果您将这些连接也变成外部连接,它会起作用:

SELECT
    r.id,json_agg(u.name) FILTER (WHERE u.name IS NOT NULL) as active_users,json_agg(u1.name) FILTER (WHERE u1.name IS NOT NULL) as inactive_users
FROM rooms r
LEFT JOIN json_array_elements(active_users) as elems
    ON TRUE
LEFT JOIN json_array_elements(inactive_users) as elems1
    ON TRUE
LEFT JOIN users u 
    ON u.id = elems::TEXT::INT
LEFT JOIN users u1 ON 
    u1.id = elems1::TEXT::INT 
GROUP BY r.id;

您会注意到我还在选择中添加了 FILTER,因此从聚合中排除了空用户名。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...