Выберите строку первых ненулевых значений в разреженной таблице
Используя следующую таблицу:
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
Ответы
Ответ 1
Функция окна 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
оценивается как TRUE
или FALSE
. FALSE
сортирует перед TRUE
. Таким образом, ненулевые значения идут первыми. Далее следует ts
по ts
(столбец отметки времени, как вы прокомментировали), и вы получите его в одном SELECT
.
Это было бы проще, если бы Postgres поддерживал IGNORE NULLS
. Руководство:
Стандарт SQL определяет RESPECT NULLS
или IGNORE NULLS
вариант для lead
, lag
, first_value
, last_value
и nth_value
. Это не реализовано в PostgreSQL: поведение всегда совпадает со стандартным значением по умолчанию, а именно RESPECT NULLS
.
Одно из немногих упущений в отношении стандартного SQL в этой области.
дБ <> скрипка здесь
SQL Fiddle.
Ответ 2
Вы должны определить порядок (первичный ключ или что-то еще), чтобы получить значение FIRST не null. Поэтому я использовал столбец 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
Ответ 3
Вы можете сделать это с помощью функций окна. Я разделил результат на 2 части, а затем использовал этот раздел для функции row_number
- с нулевыми значениями
- имеющий действительный действительный
Затем, используя базовый case
, чтобы получить те, которые имеют row_number
как 1
и которые имеют в них 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
, которое помогает узнать, какая из записей была впервые вставлена, мы используем ее в порядке возрастания в нашей оконной функции
Ответ 4
Не уверен, правильно ли я получил вопрос
как это кажется довольно простым в принципе.
Попробуйте этот запрос.
SQL Fiddle: 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