删除空值,直到第一个值不为空

时间:2014-02-17 21:43:21

标签: sql postgresql null window-functions

我的数据集中的公司每天都有时间序列并使用PostgreSQL 对于每个公司,应删除column3中所有NULL为空的行,直到此公司的此列中的第一个NOT NULL条目为止。然后,使用NOT NULL的该公司的最后一个可观察值的值填充所有连续缺失值。

您可以想象以下示例数据:

        date           company        column3
1 2004-01-01             A               5  
2 2004-01-01             B               NULL
3 2004-01-01             C               NULL  
4 2004-01-02             A               NULL
5 2004-01-02             B               7
6 2004-01-02             C               NULL
7 2004-01-03             A               6
8 2004-01-03             B               7
9 2004-01-03             C               9    
10 2004-01-04            A               NULL
11 2004-01-04            B               NULL
12 2004-01-04            C               NULL

如果我设法编写一个提供

的查询,那就太好了
        date           company        column3
1 2004-01-01             A               5  
2 2004-01-02             A               5
3 2004-01-02             B               7
4 2004-01-03             A               6
5 2004-01-03             B               7
6 2004-01-03             C               9
7 2004-01-04             A               6
8 2004-01-04             B               7
9 2004-01-04             C               9

我试过了:

SELECT a.date, a.company, COALESCE(a.column3, (SELECT b.column3 FROM mytable b 
WHERE b.company=a.company AND b.colmun3 IS NOT NULL ORDER BY b.company=a.company 
DESC LIMIT 1)) FROM mytable a;

代码存在两个问题:

  1. 它不会删除所有具有NULL值的记录,直到第一个NOT NULL值,但是  填写所有缺失值。
  2. ...在列中进行第一次观察,而不是在之前的最后一次观察  缺失值。

2 个答案:

答案 0 :(得分:1)

尝试:

SELECT *
FROM (
  SELECT id,
         date,
         company,
         case when column3 is not null
              then column3
              else (
                     SELECT column3
                     FROM mytable t1
                     WHERE t1.company = t.company
                       AND t1.date < t.date
                       AND t1.column3 IS NOT NULL
                     ORDER BY t1.date DESC LIMIT 1
                    )
          end column3
  FROM mytable T
) AS subq
WHERE column3 IS NOT NULL;

演示:http://sqlfiddle.com/#!15/0cdce/12

答案 1 :(得分:1)

我建议使用两个子查询级别window functions而不是相关的子查询:

SELECT *
FROM  (
   SELECT the_date, company, max(col3) OVER (PARTITION BY company, grp) AS col3
   FROM (
      SELECT *, count(col3) OVER (PARTITION BY company ORDER BY the_date) AS grp
      FROM   tbl
      ) sub1
   ) sub2
WHERE  col3 IS NOT NULL
ORDER  BY the_date, company;

生成请求的结果。

-> SQLfiddle

这假定每(company, the_date)个唯一条目。对于只有几行的表,应该快得多。一个(唯一来强制执行唯一性?!)索引将有助于提高性能:

CREATE INDEX tbl_company_date_idx ON tbl (company, the_date);

如何?

聚合函数count()在计数时忽略NULL值。用作聚合窗函数,它根据默认窗口定义RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW计算列的运行计数。这导致计数对具有NULL值的行“卡住”,从而形成共享相同(非空)值的对等组。

在第二个窗口函数中,使用max()可以轻松提取每个组的唯一非空值。第一个非null值之前的组保留NULL,这在最终的SELECT中很容易消除。

在这个密切相关的答案中有更多解释:
Retrieve last known value for each column of a row