使用滞后(N)值填充NULL列值

时间:2014-05-28 20:15:33

标签: 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);

示例代码创建一个这样的表:

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,但表现很好。

2 个答案:

答案 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