在稀疏表中选择一行第一个非空值

时间:2013-12-23 07:45:45

标签: sql postgresql null window-functions

使用下表:

A | B    | C    | ts
--+------+------+------------------
1 | null | null | 2016-06-15 10:00
4 | null | null | 2016-06-15 11:00 
4 |    9 | null | 2016-06-15 12:00
5 |    1 |    7 | 2016-06-15 13:00

如何在N行的运行窗口中选择每列的第一个非空值? “第一个”由列ts中的时间戳顺序定义。查询上表将导致:

A | B | C
--+---+---
1 | 9 | 7

4 个答案:

答案 0 :(得分:15)

窗口函数first_value()允许一个相当简短和优雅的解决方案:

SELECT first_value(a) OVER (ORDER BY a IS NULL, ts) AS a
     , first_value(b) OVER (ORDER BY b IS NULL, ts) AS b
     , first_value(c) OVER (ORDER BY c IS NULL, ts) AS c
FROM   t
LIMIT  1;

a IS NULL评估为TRUEFALSEFALSE之前TRUE排序。这样,非空值首先出现。接下来按ts排序(您评论的时间戳列),然后您就可以在一个SELECT中找到它。

如果Postgres支持IGNORE NULLS,这会更简单。 The manual:

  

SQL标准定义了RESPECT NULLSIGNORE NULLS选项   leadlagfirst_valuelast_valuenth_value。这不是   在PostgreSQL中实现:行为总是与   标准的默认值,即RESPECT NULLS

该领域关于标准SQL的少数遗漏之一。

db<>小提琴here
SQL Fiddle.

答案 1 :(得分:3)

您应该定义一个订单(主键或其他内容)以获取FIRST非空值。所以我使用ID列来排序表格中的行。

select 
(select A from t where A is not null ORDER BY id LIMIT 1),
(select b from t where b is not null ORDER BY id LIMIT 1),
(select c from t where c is not null ORDER BY id LIMIT 1)

SQLFiddle demo

答案 2 :(得分:1)

您可以使用window functions执行此操作。我已将结果分为两部分,然后将此分区用于row_number window function

  1. 具有空值
  2. 拥有有效的有效
  3. 然后,使用基本case来获取row_number1并且其中包含not null值的

    SQLFIDDLE

    SELECT
        max ( CASE
                WHEN a_row_num = 1 AND a IS NOT NULL THEN a
              END ) AS A,
        max ( CASE
                WHEN b_row_num = 1 AND B IS NOT NULL THEN B
              END ) AS B,
        max ( CASE
                WHEN c_row_num = 1 AND C IS NOT NULL THEN C
              END ) AS C
    FROM
        (
          SELECT
              a,
              row_number ( ) over ( partition BY a IS NULL ORDER BY ID ) a_row_num,
              b,
              row_number ( ) over ( partition BY b IS NULL ORDER BY ID ) b_row_num,
              c,
              row_number ( ) over ( partition BY c IS NULL ORDER BY ID ) c_row_num
          FROM
              test
        ) AS sub_query
    

    <强>输出:

    | A | B | C |
    |---|---|---|
    | 1 | 9 | 7 |
    

    注意:我添加了id字段,这有助于了解哪些记录首次插入,我们在窗口函数中按升序使用

答案 3 :(得分:0)

不确定我是否正确地提出了问题 因为它看起来很简单。
试试这个查询
SQL小提琴:http://sqlfiddle.com/#!11/ac585/8

WITH t0 AS
(
    SELECT A FROM
    TableName t0
    WHERE (A IS NOT NULL)
    ORDER BY ID ASC
    LIMIT 1
),

t1 AS
(
    SELECT B FROM
    TableName
    WHERE (B IS NOT NULL)
    ORDER BY ID ASC
    LIMIT 1
),

t2 AS

(
    SELECT C FROM
    TableName
    WHERE (C IS NOT NULL)
    ORDER BY ID ASC
    LIMIT 1
)

SELECT t0.A, t1.B, t2.C
FROM
t0
JOIN t1 ON 1=1
JOIN t2 ON 1=1