CUBE +外连接=额外的NULL行

时间:2016-12-22 18:34:53

标签: sql postgresql outer-join cube rolap

当我在带有OUTER JOIN的查询中使用PostgreSQL' CUBE时,我得到一个额外的全NULL行,它不能与多维数据集本身区分开#&# 34;一切都结合了#34;全NULL结果。

CREATE TABLE species
  ( id    SERIAL PRIMARY KEY,
    name  TEXT);

CREATE TABLE pet
  ( species_id INTEGER REFERENCES species(id),
    is_adult   BOOLEAN, 
    number     INTEGER)
;

INSERT INTO species VALUES
  (1, 'cat'), (2, 'dog');

INSERT INTO pet VALUES
  (1, true, 3), (1, false, 1), (2, true, 1), (null, true, 2);

好的,总共有7只宠物:

SELECT SUM(number) FROM pet;
 sum
-----
   7
(1 row)

现在查看多维数据集的总行:

SELECT * FROM (
        SELECT name, is_adult, SUM(number)
        FROM   pet p
        JOIN   species s ON (p.species_id = s.id)
        GROUP BY CUBE (name, is_adult)) subq
WHERE name IS NULL
AND   is_adult IS NULL;

 name | is_adult | sum
------+----------+-----
      |          |   5
(1 row)

5只宠物?哦,是的,因为没有种类的宠物被包括在内。我需要一个外部联接。

SELECT * FROM (
        SELECT name, is_adult, SUM(number)
        FROM   pet p
        LEFT OUTER JOIN   species s ON (p.species_id = s.id)
        GROUP BY CUBE (name, is_adult)) subq
WHERE name IS NULL
AND   is_adult IS NULL;

 name | is_adult | sum 
------+----------+-----
      |          |   2
      |          |   7
(2 rows)

我的多维数据集有2个全空行;第二个是我想要的答案。

我半理解这里发生的事情:NULL值用于表示两个不同的事物("多维数据集已经汇总了所有这些列的值"或者"这一行在右边的桌子上没有孩子")。我只是不知道如何解决它。

1 个答案:

答案 0 :(得分:3)

  

NULL值用于表示两个不同的事物("多维数据集具有   卷起所有这些专栏的价值观#34;或者"这一行没有孩子   右边的表")。

为了区分一个null和另一个null,您可以使用grouping(...)函数,请参见此处的表9-55:https://www.postgresql.org/docs/9.6/static/functions-aggregate.html#FUNCTIONS-GROUPING-TABLE

  

GROUPING(args ...)整数位掩码,指示哪些参数   未包含在当前分组集中。
分组   操作与分组集一起使用(参见章节   7.2.4)区分结果行。 GROUPING操作的参数实际上没有被评估,但它们必须完全匹配   在关联查询的GROUP BY子句中给出的表达式   水平。分配最右边的参数为   最不重要的一点;如果对应的表达式,每个位为0   包含在分组集生成的分组标准中   结果行,如果不是,则为1。

 name | is_adult | sum 
------+----------+-----
      |          |   2
      |          |   7
     

第二个是我想要的答案。

试试这个:

SELECT name, is_adult, SUM(number)
FROM   pet p
LEFT OUTER JOIN   species s ON (p.species_id = s.id)
GROUP BY CUBE (name, is_adult)
HAVING grouping(name,is_adult) = 3

name |is_adult |sum  |
-----|---------|-----|
     |         |7    |

请同时检查此查询以了解grouping函数的工作原理:

SELECT name, is_adult, SUM(number), grouping(name,is_adult)
FROM   pet p
LEFT OUTER JOIN   species s ON (p.species_id = s.id)
GROUP BY CUBE (name, is_adult)

name |is_adult |sum |grouping |
-----|---------|----|---------|
cat  |false    |1   |0        |
cat  |true     |3   |0        |
cat  |         |4   |1        |
dog  |true     |1   |0        |
dog  |         |1   |1        |
     |true     |2   |0        |
     |         |2   |1        |
     |         |7   |3        |
     |false    |1   |2        |
     |true     |6   |2        |