pgsql-列数未知的数据透视表

时间:2018-10-17 10:49:12

标签: sql postgresql pivot-table

我正在尝试在pgsql函数中创建并返回数据透视表。我遇到的问题是该函数要返回的列数取决于用户选择的日期范围。

我目前正在使用colpivot函数(https://github.com/hnsl/colpivot/blob/master/README.md),它在标准查询中可以正常使用,但在函数中却无法正常工作,因为需要在调用时设置返回类型。

方法

步骤1:

create  temp table _test (
dt timestamp without time zone, id integer,  NumericValue numeric
)

步骤2:

insert into _test(dt , id ,NumericValue)
SELECT DISTINCT "T03017_PSR_LOG"."DateTime", 
    "T03017_PSR_LOG"."ID",
    "T03017_PSR_LOG"."NumericValue"
FROM "T03017_PSR_LOG"
INNER JOIN "T03002_PSR_TAG_REG" ON "T03017_PSR_LOG"."TagID" = "T03002_PSR_TAG_REG"."TagID"
WHERE "T03017_PSR_LOG"."DateTime" > 2018-10-02 AND "T03017_PSR_LOG"."DateTime" < 2018-10-07,    
ORDER BY "DateTime", "ID";

步骤3:

select colpivot('_test_pivoted', 'select * from _test', array['tagid'], array['dt'], '#.numericvalue', null);

select * from _test_pivoted order by tagid;

如果将上述内容作为标准查询运行,它将返回类似以下内容的内容:

ID   2018-10-03   2018-10-04   2018-10-05   2018-10-06

10   1405717.00   1453189.00   1499992.00   1546791.00
11   359102.00    371282.00    383042.00    395047.00

我需要类似上表的内容才能从函数中返回,其中datetime范围是将2个变量传递给函数,但是我似乎找不到解决方案,因为我不确定如何设置返回值由于返回的列具有动态特性,因此请在函数顶部输入

1 个答案:

答案 0 :(得分:0)

这看起来有点麻烦,但是我不知道有什么方法可以返回可变数量的列,我认为最好的选择是使用数组。

在没有任何数据知识的情况下,我只能假设您有数据空白,这意味着并非每个id都有每个日期的数据点,因此我要做的第一项任务是填补空白并确定日期和日期的每种可能组合ID。

with all_dates as (
  select distinct dt from _test
),
all_ids as (
  select distinct id from _test
)
select id, dt
from all_dates
cross join all_ids

从那里,我将其连接回原始数据集,以便每一行数组中的每个元素都引用相同的内容(即,如果一行中的元素#5是2017年11月,则意味着每一行)。

这是整个查询的样子:

with all_dates as (
  select distinct dt from _test
),
all_ids as (
  select distinct id from _test
),
all_combo as (
  select id, dt
  from all_dates
  cross join all_ids
),
pivot_data as (
  select
    a.dt, a.id, coalesce (t.NumericValue, 0) as NumericValue
  from
    all_combo a
    left join _test t on
      a.id = t.id and
      a.dt = t.dt
  order by
    a.id, a.dt
)
select
  id, array_agg(NumericValue) as valuez
from pivot_data
group by id

这会有些重复(每行的值都相同),但是您也可以将日期范围作为数组包括进来:

select
  id, array_agg(dt) as dates, array_agg(NumericValue) as valuez