【问题标题】:How to include null values in `tablefunc` query in postgresql?如何在 postgresql 的“tablefunc”查询中包含空值?
【发布时间】:2012-10-15 10:49:42
【问题描述】:

我正在尝试使用postgresql 中的crosstab 函数来创建pivot table。但是,我很难理解如何在查询中构造我的 SQL。我的数据由四列组成,如下所示:

我使用以下代码创建此表:

CREATE TABLE ct(id SERIAL, zone_id int, group_id int, area double precision);
INSERT INTO ct(zone_id, group_id, area) VALUES(1,2,6798.50754160784);
INSERT INTO ct(zone_id, group_id, area) VALUES(1,3,10197.7613124118);
INSERT INTO ct(zone_id, group_id, area) VALUES(2,1,85708.8676744647);
INSERT INTO ct(zone_id, group_id, area) VALUES(2,2,56006.5971338327);
INSERT INTO ct(zone_id, group_id, area) VALUES(2,3,5584.33145616642);
INSERT INTO ct(zone_id, group_id, area) VALUES(2,5,8611.99732832252);
INSERT INTO ct(zone_id, group_id, area) VALUES(2,6,36103.5509183704);
INSERT INTO ct(zone_id, group_id, area) VALUES(2,8,9801.14541428806);
INSERT INTO ct(zone_id, group_id, area) VALUES(5,1,45796.0020793546);

并密切关注postgresql 文档,我在crosstab 查询中使用以下代码:

SELECT *
FROM crosstab(
  'select zone_id, group_id, area
   from ct
   ')
AS ct(row_name integer, 
      g_1 double precision, 
      g_2 double precision, 
      g_3 double precision, 
      g_4 double precision, 
      g_5 double precision, 
      g_6 double precision, 
      g_7 double precision, 
      g_8 double precision);

这导致下表不是我想要的:

例如,在第二行,我想要以下值:

85708.8676744647, 56006.5971338327, 5584.33145616642, NULL, 8611.99732832252, 36103.5509183704, NULL, 9801.14541428806

取而代之的是:

85708.8676744647, 56006.5971338327, 5584.33145616642, 8611.99732832252, 36103.5509183704, 9801.14541428806

但是,null 的值似乎被忽略了,因此我的列名 g1g8 与原始组不对应。

【问题讨论】:

    标签: sql postgresql table-functions


    【解决方案1】:

    使用crosstab() variant with two parameters

    SELECT * FROM crosstab(
       'SELECT zone_id, group_id, area
        FROM   ct
        ORDER  BY 1,2'
    
       ,'SELECT g FROM generate_series(1,8) g'  -- ! Provide values explicitly
       )
    AS ct(
         row_name integer
       , g_1 float8, g_2 float8
       , g_3 float8, g_4 float8
       , g_5 float8, g_6 float8
       , g_7 float8, g_8 float8);
    

    从而明确声明哪个值进入哪个输出列。所以函数知道在哪里填写NULL 值。在这种情况下,generate_series() 可以方便地提供 8 行的数字 1-8。 VALUES 表达式将是另一种选择:

    'VALUES (1), (2), (3), (4), (5), (6), (7), (8)'
    

    另外,不要忘记第一个参数查询中的ORDER BY 子句。

    我提供了detailed explanation in this related answer

    【讨论】:

    • 感谢您的明确答复。 ORDER BY 1,2的目的是什么?
    【解决方案2】:

    我无法让它在 Demo 中工作,因为我无法创建 tablefunc 扩展,但它可以在运行 9.2.1 的桌面上工作:

    SELECT *
    FROM crosstab(' 
        select 
            s.zone_id, s.group_id, area
        from 
            ct
            right join (
                (select distinct zone_id from ct) z(zone_id)
                cross join
                generate_series(1, 8) g(group_id)
            ) s on s.group_id = ct.group_id and s.zone_id = ct.zone_id
        order by s.zone_id, s.group_id
    ') AS ct (
        row_name integer, 
        g_1 double precision, 
        g_2 double precision, 
        g_3 double precision, 
        g_4 double precision, 
        g_5 double precision, 
        g_6 double precision, 
        g_7 double precision, 
        g_8 double precision
    );
    

    【讨论】:

      猜你喜欢
      • 2020-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-20
      • 2018-07-20
      • 1970-01-01
      相关资源
      最近更新 更多