array_agg group by和null

时间:2014-03-16 22:23:57

标签: postgresql null group-by left-join generate-series

鉴于此表:

SELECT * FROM CommodityPricing order by dateField

"SILVER";60.45;"2002-01-01"
"GOLD";130.45;"2002-01-01"
"COPPER";96.45;"2002-01-01"
"SILVER";70.45;"2003-01-01"
"GOLD";140.45;"2003-01-01"
"COPPER";99.45;"2003-01-01"
"GOLD";150.45;"2004-01-01"
"MERCURY";60;"2004-01-01"
"SILVER";80.45;"2004-01-01"

截至2004年,COPPER被淘汰并引入了汞 如何为(array_agg(value order by date desc) ) [1]获取NULL COPPER的值?

select commodity,(array_agg(value order by date desc) ) --[1]
from CommodityPricing
group by commodity

"COPPER";"{99.45,96.45}"
"GOLD";"{150.45,140.45,130.45}"
"MERCURY";"{60}"
"SILVER";"{80.45,70.45,60.45}"

2 个答案:

答案 0 :(得分:0)

SQL Fiddle

select
    commodity,
    array_agg(
        case when commodity = 'COPPER' then null else price end
        order by date desc
    )
from CommodityPricing
group by commodity
;

答案 1 :(得分:0)

To" pad"在结果数组中缺少具有NULL值的行,在完整的行网格 LEFT JOIN 实际值的网格上构建查询。
鉴于此表定义:

CREATE TEMP TABLE price (
    commodity text
  , value     numeric
  , ts        timestamp  -- using ts instead of the inappropriate name date 
);

我使用generate_series()获取表示年份的时间戳列表,并CROSS JOIN列出所有商品的唯一列表(SELECT DISTINCT ...)。

SELECT commodity, (array_agg(value ORDER BY ts DESC)) AS years
FROM   generate_series ('2002-01-01 00:00:00'::timestamp
                      , '2004-01-01 00:00:00'::timestamp
                      , '1y') t(ts)
CROSS  JOIN (SELECT DISTINCT commodity FROM price) c(commodity)
LEFT   JOIN price p USING (ts, commodity)
GROUP  BY commodity;

结果:

COPPER  {NULL,99.45,96.45}
GOLD    {150.45,140.45,130.45}
MERCURY {60,NULL,NULL}
SILVER  {80.45,70.45,60.45}

SQL Fiddle.
我将数组转换为小提琴中的文本,因为显示很糟糕,否则会吞下NULL值。