2017-02-13 139 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;