PostgreSQL:将多个日期列动态转置为行

PostgreSQL: transpose multiple date columns dynamically to rows

如果之前有人问过这个问题,我深表歉意。我已经搜索了 Postgres 手册和许多 SO 答案,但仍然找不到解决方案。我正在努力寻找正确的 SQL (postgres) 命令来转换以下 table:

| client | starts_on  | ends_on    |
|--------|------------|------------|
| ACME   | 2019-12-01 | 2020-02-28 |

进入所需的输出:

| client | year       | month      |
|--------|------------|------------|
| ACME   | 2019       | 12         |
| ACME   | 2020       | 1          |
| ACME   | 2020       | 2          |

应该用 crosstab 来完成吗?如果是这样,我该如何使用 date_trunc 功能?

SELECT
    *
FROM
    crosstab ('SELECT client, date_trunc(' year ', ends_on), date_trunc(' month ', ends_on)
         FROM example_table') 
AS ct ("Client" text,
        "Year" int,
        "Month" int);

这将引发以下错误:

Query 1 ERROR: ERROR: syntax error at or near "month" LINE 4: crosstab ('SELECT client, date_trunc('month', ends_on), dat...

任何指导将不胜感激!

这不是 pivoting/cross 选项卡问题。您需要为两个日期之间的所有月份生成行。使用 generate_series():

select t.client, extract(year from gs.dte), extract(month from gs.dte)
from t cross join lateral
     generate_series(t.starts_on, t.ends_on, interval '1 month') gs(dte);

Here 是一个 db<>fidle。

尽管原始问题似乎是一个语义问题,引用包含引号的字符串 可能对未来的读者有用:


CREATE TABLE example_table
        ( client text
        , ends_on timestamp
        );

SELECT *
FROM public.crosstab (
$qq$
SELECT client, date_trunc('year', ends_on), date_trunc('month', ends_on)
         FROM example_table
$qq$
) AS ct ("Client" text, "Year" int, "Month" int);