将多行合并为单行

Com*_*mic 6 postgresql aggregate pivot aggregate-filter

在 PostgreSQL 9.5 中,我有一个名为的表reports

CREATE TABLE public.reports (
  id BIGSERIAL PRIMARY KEY,
  id_station character(11) NOT NULL,
  date date NOT NULL,
  element character(4) NOT NULL,
  value smallint NOT NULL
);
Run Code Online (Sandbox Code Playgroud)

对于每个站(id_station列)和每一天(date列),我可能有多个值类型(元素列) : TMIN, TMAX, TAVG(有时这些值不存在:对于给定的一天,我可能只有 aTMIN和 a TMAX)。

这是一个(假)样本:

22;"FR069029001";"1925-01-01";"TMAX";130
23;"FR069029001";"1925-01-01";"TMIN";-25
24;"FR069029001";"1925-01-01";"TAVG";0
Run Code Online (Sandbox Code Playgroud)

我想使用此表将每个站点和每天的这些值合并在一行中:

CREATE TABLE public.reports_con (
id SERIAL PRIMARY KEY,
id_station character(11) NOT NULL,
date date NOT NULL,
tmin smallint,
tmax smallint,
tavg smallint
);
Run Code Online (Sandbox Code Playgroud)

我想达到这个结果:

454;"FR069029001";"1925-01-01";-25;130;0
Run Code Online (Sandbox Code Playgroud)

如何在PostgreSQL中以这种方式整合数据?与CREATE TABLE AS

我知道它必须是这样的递归查询(人类语言):

For each day:
    For each station:
        Find values for TMIN, TMAX, TAVG
Insert the results in reports_con in a single row with day and station
Run Code Online (Sandbox Code Playgroud)

我开始学习 SQL 并希望在 PostgreSQL 中实现这一点(而不是使用 Python 或编程语言)。你能帮我么?

Erw*_*ter 4

由于目标表显然存在,CREATE TABLE AS因此与解决方案无关。而且您当然也不需要递归查询。

对于仅三列,您可以使用条件聚合:

INSERT INTO reports_con (id_station, date, tmin, tmax, tavg)
SELECT id_station, date
     , min(value) FILTER (WHERE element = 'TMIN') AS tmin
     , min(value) FILTER (WHERE element = 'TMAX') AS tmax
     , min(value) FILTER (WHERE element = 'TAVG') AS tavg
FROM   reports
GROUP  BY id_station, date
ORDER  BY id_station, date;
Run Code Online (Sandbox Code Playgroud)

聚合FILTER子句需要 Postgres 9.4。旧版本的详细信息和替代方案:

对于更多列或大量行(并且您需要更好的性能),请考虑实际crosstab()查询。特别困难的是您的密钥由两列组成,但您需要一列用于crosstab(). 在这些相关答案中生成类似的代理键row_number()