我有一个简单的表格,缺少"某人"柱。我想用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。
更新: 阅读文档,我发现滞后需要一个可选参数[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,但表现很好。
答案 0 :(得分:2)
这是一个输出正确的 - 根据你所展示的。为了扩展测试,我输入了一些值,创建了两个不同的名称,它们之间有间隙。
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), (1, NULL), (1, 'James'), (1, NULL),
(2, 'Roybal'), (2, NULL), (2, NULL),
(3, NULL), (3, 'Truman'), (3, NULL), (3, NULL);
我无法弄清楚这是否适用于分析(无论如何不使用LAG),但这里有一个解决方案,它有一个连接和一个子查询。真的很简单。
SELECT lt.ID ID, lt.Natural_key,
CASE WHEN lt.Somebody IS NULL
THEN lt1.Somebody
ELSE lt.Somebody END SomeBody
FROM lag_test lt
LEFT JOIN lag_test lt1
ON lt1.ID =(
SELECT MAX( ID )
FROM lag_test
WHERE Natural_key = lt.Natural_key
and ID < lt.ID
AND SomeBody IS NOT NULL);
请参阅SQL Fiddle沙箱。
答案 1 :(得分:1)
不能测试但是试试这个:
SELECT lt.id, lt.natural_key, l.somebody from lag_test lt inner join (select
lt.natural_key, lt.somebody from lag_test lt inner join (select MAX(id) as LastID,
somebody from lag_test WHERE NOT somebody is null GROUP BY somebody) as lson
lt.id=ls.LastID) as l on lt.natural_key=l.natural_key
可能不是最紧凑的方式,但它对我有用。
这是结果
id natural_key somebody
----------------------------
1 1 Kirk
2 1 Kirk
3 1 Kirk
4 1 Kirk
5 2 Roybal
6 2 Roybal
7 2 Roybal