PostgreSQL 查询:左外部连接 "where",但如果不存在则为空值

PostgreSQL query: left outer join with "where" but also null values if not existing

我在无法修改的 PostgreSQL 数据库中有两个 table(我只是想从中获取信息的 COTS 软件)。

一个有用户信息:

| id | username | mail          |
+----+----------+---------------+
| 1  | admin    | admin@xzy.com |
| 2  | user     | user@xzy.com  |

...和一个额外的 table 具有用户属性:

| user_id | attribute_name  | attribute_value   |
+---------+-----------------+-------------------+
| 1       | active          | true              |
| 1       | loginDateMillis | 1652176627        |
| 2       | active          | true              |

我需要的是所有用户及其 loginDateMillis(如果存在),否则为“null”或空,例如:

| id | username | mail          | attribute_value |
+----+----------+---------------+-----------------+
| 1  | admin    | admin@xzy.com | 1652176627      |
| 2  | user     | user@xzy.com  | null            |

起初我尝试将两个 table 与 where 条件连接到 select 只有 attribute_name = 'loginDateMillis',但后来我过滤掉空行:

> select u.id, u.username, u.mail, a.attribute_value
  from users u
  left outer join user_attributes a
  on a.user_id = u.id
  where a.attribute_name = 'loginDateMillis';

| id | username | mail          | attribute_value |
+----+----------+---------------+-----------------+
| 1  | admin    | admin@xzy.com | 1652176627      |

我能找到的唯一解决方案是为每个用户获取一行,还有属性,是按用户列分组并使用 array_agg 函数:

> select u.id, u.username, u.mail, array_agg(a.attribute_name), array_agg(a.attribute_value)
  from users u
  left outer join user_attributes a
  on a.user_id = u.id
  group by (u.id, u.username, u.mail);

| id | username | mail          | attribute_name            | attribute_value    |
+----+----------+---------------+---------------------------+--------------------+
| 1  | admin    | admin@xzy.com | {active, loginDateMillis} | {true, 1652176627} |
| 2  | user     | user@xzy.com  | {active}                  | {true}             |

这“还可以”,因为我可以在我的应用程序中过滤数组,但也许我在这里遗漏了一些明显的东西?非常感谢。

如果将 WHERE 子句中的逻辑移动到 ON 子句中,它应该会按预期工作:

select u.id, u.username, u.mail, a.attribute_value
from users u
left join user_attributes a
on a.user_id = u.id and a.attribute_name = 'loginDateMillis';