我使用 PostgreSQL 14 来管理一个存储医生表更新的表:用户可以更新医生的名字、姓氏和/或年龄。更新操作未触及的字段具有 NULL
值。
这是涉及两名不同医务人员的四次编辑的示例。 ID 为 3 的医生收到了三个更新:前两个正在更新 age
字段中,第三个触及 first_name
:
SELECT * FROM medic_edits;
我想合并此表,以便在结果表中每个医生有一行,提供累积编辑。这是我当前的查询及其产生的输出:
SELECT
medic_id,
(ARRAY_REMOVE(ARRAY_AGG(first_name ORDER BY id DESC), NULL))[1] AS first_name,
(ARRAY_REMOVE(ARRAY_AGG(last_name ORDER BY id DESC), NULL))[1] AS last_name,
(ARRAY_REMOVE(ARRAY_AGG(age ORDER BY id DESC), NULL))[1] AS last_name
FROM medic_edits
GROUP BY medic_id
;
这正是我期望的输出,但我怀疑 ARRAY_REMOVE/ARRAY_AGG
逻辑有点浪费。我想知道这里是否有一种方法可以利用分区来获得良好的利润,FIRST_VALUE
函数看起来非常相关。
最佳答案
是的,这是浪费。我希望这会更快:
SELECT DISTINCT ON (medic_id)
medic_id
, first_value(first_name) OVER (PARTITION BY medic_id ORDER BY CASE WHEN first_name IS NOT NULL THEN id END) AS first_name
, first_value(last_name) OVER (PARTITION BY medic_id ORDER BY CASE WHEN last_name IS NOT NULL THEN id END) AS last_name
, first_value(age) OVER (PARTITION BY medic_id ORDER BY CASE WHEN age IS NOT NULL THEN id END) AS age
FROM medic_edits;
对于降序的 id
值,请改用:
first_value(first_name) OVER (PARTITION BY medic_id ORDER BY CASE WHEN first_name IS NOT NULL THEN id END DESC NULLS LAST) AS first_name
参见:
但可能还有更快的方法。还取决于确切的表定义、基数和数据分布。
参见:
关于DISTINCT ON
:
在单个 SELECT
中工作,因为 DISTINCT
或 DISTINCT ON
是在窗口函数之后应用的。请参阅:
旁白:“年龄”将会迅速腐烂。它通常更适合存储生日。
关于sql - 使用 ARRAY_AGG 获取列中的第一个非 NULL 值是否浪费?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73755206/