Kir*_*bal 5 sql postgresql postgresql-9.3
我有一个简单的表,该表缺少“某人”列的值。我想用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);
Run Code Online (Sandbox Code Playgroud)
示例代码创建一个像这样的表:
id natural_key somebody
-- ----------- --------
1 1 NULL
2 1 Kirk
3 1 NULL
4 2 Roybal
5 2 NULL
6 2 NULL
Run Code Online (Sandbox Code Playgroud)
到目前为止,我有这个:
SELECT id,
natural_key,
COALESCE(somebody, lag(somebody) OVER (PARTITION BY natural_key)) somebody
FROM lag_test
ORDER BY natural_key, id;
Run Code Online (Sandbox Code Playgroud)
哪个返回:
id natural_key somebody
-- ----------- --------
1 1 NULL
2 1 Kirk
3 1 Kirk
4 2 Roybal
5 2 Roybal
6 2 NULL
Run Code Online (Sandbox Code Playgroud)
我希望它返回:
id natural_key somebody
-- ----------- --------
1 1 NULL
2 1 Kirk
3 1 Kirk
4 2 Roybal
5 2 Roybal
6 2 Roybal
Run Code Online (Sandbox Code Playgroud)
基本问题是:如何获取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;
Run Code Online (Sandbox Code Playgroud)
这解决了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;
Run Code Online (Sandbox Code Playgroud)
仅适用于不包含管道“ |”的数据 符号。Kinda hacky,但是性能不错。
根据您所显示的内容,这是一个具有正确输出的输出。为了扩展测试,我输入了更多值,创建了两个不同的名称,它们之间有一个间隙。
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);
Run Code Online (Sandbox Code Playgroud)
我不知道这是否适用于分析(无论如何都不使用 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);
Run Code Online (Sandbox Code Playgroud)
请参阅SQL Fiddle沙箱。