2017-02-13 135 views
1

我想獲取一條包含布爾標誌的記錄:如果特定結果集中的列至少有一個NOT NULL值,則爲true,如果所有值都爲NULL,則爲false。優化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()如果至少有一個值爲真,則返回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()骨料都將返回true只有當所有的值是true。

+0

那麼'bool_or'似乎已經被優化了。它的名字承諾,當第一個「真」值被發現時,它停止聚合。可能並非如此。 – Paul

1

這回1 NOT NULL列:

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

此添加NOT NULL列數:

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是的,我剛看到Laurenz的回答。 :$ –

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;