2017-02-13 1 views
1

Я пытаюсь получить одну запись, содержащую логические флаги: true, если столбец в определенном результирующем наборе имеет хотя бы одно значение NOT NULL и false, если все значения NULL.Оптимизировать флаги NULL/NOT NULL Запрос PostgreSQL

Примеры данных результирующего набора

SELECT "my column 1", "my column 2", "my column 3", "my column 4", "my column 5" 
FROM my_data 
WHERE date BETWEEN :start AND :end 

"my column 1" "my column 2" "my column 3" "my column 4" "my column 5" 
    NULL   NULL   25.2   NULL   1.12 
    15.28   NULL   NULL   NULL   2.25 
    NULL   NULL   13.9   NULL   3.03 
    359.00  NULL   125.5   NULL   4.15 
    NULL   NULL   152.2   NULL   5.99 
    NULL   NULL   NULL   NULL   6.35 

В этом случае результат должен быть:

"my column 1" "my column 2" "my column 3" "my column 4" "my column 5" 
    t    f    t    f    t 

Ведомая запрос PostgreSQL делает именно то, что мне нужно (на самом деле он завершает каждый вложенный запрос, как только первый NOT NULL), но его можно было бы оптимизировать ?:

WITH x AS (SELECT * FROM my_data WHERE date BETWEEN :start AND :end) 

SELECT 
    EXISTS(SELECT * FROM x WHERE "my column 1" IS NOT NULL) AS "my column 1", 
    EXISTS(SELECT * FROM x WHERE "my column 2" IS NOT NULL) AS "my column 2", 
    EXISTS(SELECT * FROM x WHERE "my column 3" IS NOT NULL) AS "my column 3", 
    EXISTS(SELECT * FROM x WHERE "my column 4" IS NOT NULL) AS "my column 4", 
    EXISTS(SELECT * FROM x WHERE "my column 5" IS NOT NULL) AS "my column 5" 

Я думал, что это может быть написано либо короче, либо повсеместно, без упоминания имени каждого столбца.

+0

Это удар производительности? –

+0

Вы можете использовать CASE? https://www.postgresql.org/docs/9.4/static/functions-conditional.html – lionbtt

+0

@ Ranadip Dutta: Нет, но я думал, что это может быть написано либо короче, либо повсеместно, без упоминания имени каждого столбца. – Paul

ответ

6

Другой вариант заключается в использовании bool_or() aggregate, который возвращает true, если в лизинге одно значение истинно.

SELECT bool_or("my column 1" is not null) AS "my column 1", 
     bool_or("my column 2" is not null) AS "my column 2", 
     bool_or("my column 3" is not null) AS "my column 3", 
     bool_or("my column 4" is not null) AS "my column 4", 
     bool_or("my column 5" is not null) AS "my column 5" 
FROM my_data 
WHERE date BETWEEN :start AND :end; 

Существует также bool_and() агрегат, который будет возвращать верно, только если все значения истинны.

+0

Ну, 'bool_or', кажется, оптимизирован. Его имя обещает, что оно перестанет агрегировать, когда будет найдено первое значение true. Может быть, это не так. – Paul

1

это возвращение 1 для не нулевых столбцов:

CASE WHEN "my column 1" IS NULL THEN 0 ELSE 1 END 

Это сложим число не нулевых столбцов:

COUNT(<previous case>) > 0 

Окончательная запрос:

SELECT CASE 
      WHEN COUNT(CASE WHEN "my column 1" IS NULL THEN 0 ELSE 1 END) > 0 
      THEN true 
      ELSE false 
     END, 
     -- ..... same for the other columns 
     -- , "my column 2", "my column 3", "my column 4", "my column 5" 
FROM my_data 
WHERE date BETWEEN :start AND :end 
+0

@a_horse_with_no_name Да, я только что видел Лоренца. : $ –

4
SELECT 
    count("my column 1") > 0 AS "my column 1", 
    count("my column 2") > 0 AS "my column 2", 
    count("my column 3") > 0 AS "my column 3", 
    count("my column 4") > 0 AS "my column 4", 
    count("my column 5") > 0 AS "my column 5" 
FROM my_data 
WHERE date BETWEEN :start AND :end;