【发布时间】:2014-05-28 20:15:32
【问题描述】:
我有一个简单的表,其中缺少“某人”列的值。我想用 id 字段中的先前值按升序填充 NULL 值,而不是降序值(过去的项目可能不同)。为了实验(我的实际查询要复杂得多),我不能简单地使用 UPDATE 查询来填充表,我必须将其作为 SELECT 来执行。
CREATE TABLE lag_test (id serial primary key, natural_key integer, somebody text);
INSERT INTO lag_test(natural_key, somebody)
VALUES (1, NULL), (1, 'Kirk'), (1, NULL), (2, 'Roybal'), (2, NULL), (2, NULL);
示例代码创建如下表格:
id natural_key somebody
-- ----------- --------
1 1 NULL
2 1 Kirk
3 1 NULL
4 2 Roybal
5 2 NULL
6 2 NULL
到目前为止,我有这个:
SELECT id,
natural_key,
COALESCE(somebody, lag(somebody) OVER (PARTITION BY natural_key)) somebody
FROM lag_test
ORDER BY natural_key, id;
返回这个:
id natural_key somebody
-- ----------- --------
1 1 NULL
2 1 Kirk
3 1 Kirk
4 2 Roybal
5 2 Roybal
6 2 NULL
我希望它返回这个:
id natural_key somebody
-- ----------- --------
1 1 NULL
2 1 Kirk
3 1 Kirk
4 2 Roybal
5 2 Roybal
6 2 Roybal
基本问题是:如何让 lag() 过去 N 行,以便行 id:6,natural_key:2 接收“某人”列的值?
我正在使用 PG 9.3.4。
更新: 阅读文档后,我发现 lag 需要一个可选参数 [offset],我可以在某种程度上使用它。希望有人能帮我完善一下:
SELECT id,
natural_key,
COALESCE(somebody,
lag(somebody, 1) OVER (PARTITION BY natural_key),
lag(somebody, 2) OVER (PARTITION BY natural_key),
lag(somebody, 3) OVER (PARTITION BY natural_key)
) somebody
FROM lag_test
ORDER BY natural_key, id;
这解决了 OP 中显示的有限测试集的问题。真正的问题尚未得到解答。
编辑 2:
我也发现了这个小宝石。
SELECT id, natural_key,
regexp_replace(string_agg(somebody, '|') OVER (ORDER BY id)::text, '^.*\|', '', 'g') somebody
FROM lag_test
ORDER BY natural_key, id;
仅适用于不包含管道“|”的数据象征。有点hacky,但性能很好。
【问题讨论】:
-
在匿名代码块中进行足够的更新很容易。你会接受这样的灵魂吗?
-
我不确定您所说的“充分更新”是什么意思,抱歉。
-
你想做的更新。
-
我不能使用 UPDATE 语句。例子很简单,但实际用例却很复杂。我将不胜感激与窗口功能相关的答案,而不是表更新。
-
对不起,我错过了。我担心 lag() 的解决方案会非常复杂。用户定义的功能仍然很简单。
标签: sql postgresql postgresql-9.3