我正尝试使用同一表中另一行的值更新表中的 * 多个列 *:
CREATE TEMP TABLE person (
pid INT
, name VARCHAR(40)
, dob DATE
, younger_sibling_name VARCHAR(40)
, younger_sibling_dob DATE
);
INSERT INTO person VALUES (pid, name, dob)
(1, 'John' , '1980-01-05')
, (2, 'Jimmy', '1975-04-25')
, (3, 'Sarah', '2004-02-10')
, (4, 'Frank', '1934-12-12')
;
任务是用年龄与younger_sibling_name
和younger_sibling_dob
最接近的人的姓名和生日填充younger_sibling_name
和younger_sibling_dob
,但不能比younger_sibling_name
大或年龄相同。
我可以很容易地设置较年轻的兄弟dob
,因为它是确定与相关子查询一起使用的记录的值(我认为这是一个示例?):
UPDATE person SET younger_sibling_dob = (
SELECT MAX(dob)
FROM person AS sibling
WHERE sibling.dob < person.dob);
我只是看不出有什么办法可以得到name
?
对于每个MAX选择,真实的查询将运行大约1 M行,每组100-500行,因此性能是一个问题。
编辑
在尝试了许多不同的方法之后,我决定采用这个方法,我认为它能够很好地平衡验证数据与中间结果,显示逻辑的意图,并充分执行:
WITH sibling AS (
SELECT person.pid, sibling.dob, sibling.name,
row_number() OVER (PARTITION BY person.pid
ORDER BY sibling.dob DESC) AS age_closeness
FROM person
JOIN person AS sibling ON sibling.dob < person.dob
)
UPDATE person
SET younger_sibling_name = sibling.name
,younger_sibling_dob = sibling.dob
FROM sibling
WHERE person.pid = sibling.pid
AND sibling.age_closeness = 1;
SELECT * FROM person ORDER BY dob;
3条答案
按热度按时间wqlqzqxt1#
重写2022
我预计您添加的解决方案的性能会很差,因为它做了大量不必要的工作。
当有多个具有相同
dob
的行时,该问题和添加的解决方案没有定义要选取哪一行。通常,您需要确定性选取。此查询从具有相同dob
的每组对等体中选取按字母顺序排列的名字。请根据您的需要进行调整。至少从Postgres 8.4开始工作。
需要在
dob
上使用索引才能快速,最好是在(dob, name)
上使用多列索引。子查询
sub
将整个表传递一次,并按dob
提取不同得行.①我把
name
添加到ORDER BY
中作为决胜局,以选择名字按字母顺序排列的行。在外层的
SELECT
中,将后面的dob
(next_dob
)添加到每一行中,其中lead()
--简单的,现在有不同的dob
,然后连接到next_dob
,剩下的就是简单的。如果 * 没有更年轻的人 * 存在,则没有
UPDATE
发生,列保持NULL
。关于
DISTINCT ON
和可能更快的 * 许多 * 重复项查询技术:从同一行取
dob
和name
可以保证我们保持同步。多个相关子查询不能提供这种保证,而且代价会更高。原始答案
仍然有效。
旧查询1
古老的SQLFIDLE
在CTE
cte
中,根据每个人的dop
,使用窗函数dense_rank()
获得无间隙的排名。将
cte
与其自身连接,但从第二个示例中删除dob
上的重复项。这样每个人都得到一个UPDATE
。如果多个人共享同一个dop
,则 * 同一个 * 将被选为下一个dob
上所有人的弟弟。我使用以下语句执行此操作:将
ORDER BY rnk, ...
添加到此子查询中,以便为每个dob
选择一个特定得人.旧查询2
古老的SQLFIDLE
这是可行的,因为聚合函数是在窗口函数之前应用的,而且由于两种操作都遵循排序顺序,所以速度应该很快。
不需要像查询1中那样使用后面的
DISTINCT
。结果与查询1完全相同。
同样,您可以向
ORDER BY
添加更多列,以便为每个dob
选择一个特定的人。k10s72fa2#
1)查找MAX()总是可以用NOT EXISTS(...)重写
2)除了rank()/ row_number(),您也可以在WINDOW上使用LAG()函数:
这两个版本都需要自联接子查询(或CTE),因为UPDATE不允许窗口函数。
xxls0lw83#
要获取dob和名称,您可以执行以下操作:
如果您在
dob
上有索引,则查询会执行得更快。