带有 CASE 和聚合的 PostgreSQL crosstab() 替代方案
PostgreSQL crosstab() alternative with CASE and aggregates
我想创建一个数据透视表 table 视图,显示每个 travel_mode
.
的月度预订总和
Table bookings
:
timestamp
, bookings
, provider_id
Table providers
:
provider_id
, travel_mode
Pivot table 函数和交叉表函数不用于执行此操作。所以我正在尝试使用 JOIN 和 CASE。以下是查询:
SELECT b.month,
(CASE WHEN p.travel_mode=train then b.amount end)train,
(CASE WHEN p.travel_mode=bus then b.amount end)bus,
(CASE WHEN p.travel_mode=air then b.amount end)air
FROM
(SELECT to_char(date_,month) as month, travel_mode, sum(bookings) as amount
from bookings as b
join providers as p
on b.provider_id=p.provider_id
group by b.month, p.travel_mode)
group by b.month;
但是我收到一条错误消息:
subquery in FROM must have an alias LINE 6:
当我添加别名时,它会抛出一条错误消息:
column p.travel_mode must appear in the GROUP BY clause or be used in an aggregate function
LINE 2:
最后的结果应该是这样的
Month Air Bus Train
01 Amount(air) Amount(Bus) Amount(train)
我感觉这是某个地方的小错误,但我根本无法弄清楚。
P.S。我不得不删除问题中的所有引号,因为它不允许我 post 这个。但是在实际查询中会处理这些问题。
您必须按照错误消息所述命名子查询:
SELECT b.month,
(CASE WHEN p.travel_mode=train then b.amount end)train,
(CASE WHEN p.travel_mode=bus then b.amount end)bus,
(CASE WHEN p.travel_mode=air then b.amount end)air
FROM
(SELECT to_char(date_,month) as month, travel_mode, sum(bookings) as amount
from bookings as b
join providers as p
on b.provider_id=p.provider_id
group by b.month, p.travel_mode)
**as foo** group by b.month;
移除星号使其生效。
多个问题。缺少的 table 别名只是其中之一。此查询应该有效:
SELECT month
, sum(CASE WHEN travel_mode = 'train' THEN amount END) AS train
, sum(CASE WHEN travel_mode = 'bus' THEN amount END) AS bus
, sum(CASE WHEN travel_mode = 'air' THEN amount END) AS air
FROM (
SELECT to_char(timestamp, 'MM') AS month, travel_mode, sum(bookings) AS amount
FROM bookings b
JOIN providers p USING (provider_id)
GROUP BY month, p.travel_mode
) sub
GROUP BY month;
字符串文字缺少单引号。 (您似乎已经删除了那些在错误印象下您无法 post 引用的内容。)
缺少子查询的 table 别名 - 正如第一条错误消息所说。
在外部查询中,子查询中基础 table 的 table 名称(或别名)不可见。只有子查询的 table 别名是。因为只有 一个 子查询,所以根本不需要 table 限定。
month
是输出列名称(不在基础 table 中),因此 table 限定条件 b.month
也是错误的。
您似乎想要几个月的两位数。使用 template pattern 'MM' 而不是 'month' 和 to_char()
.
外部查询中的聚合无法正常工作 - 就像您的第二条错误消息所说的那样。您必须将外部 CASE
表达式包装在聚合函数中。在这种情况下,您还不如使用 min()
或 max()
,因为在子查询之后永远不会超过一行。
仍然不清楚 date_
的来源?你是说 timestamp
? (这不是一个好的标识符)。
但是你不需要子查询开始,可以简化为:
SELECT to_char(timestamp, 'MM') AS month
, sum(CASE WHEN p.travel_mode = 'train' THEN b.bookings END) AS train
, sum(CASE WHEN p.travel_mode = 'bus' THEN b.bookings END) AS bus
, sum(CASE WHEN p.travel_mode = 'air' THEN b.bookings END) AS air
FROM bookings b
JOIN providers p USING (provider_id)
GROUP BY 1;
为了获得最佳性能,您仍应使用 crosstab()
,但:
- PostgreSQL Crosstab Query
我想创建一个数据透视表 table 视图,显示每个 travel_mode
.
Table bookings
:
timestamp
, bookings
, provider_id
Table providers
:
provider_id
, travel_mode
Pivot table 函数和交叉表函数不用于执行此操作。所以我正在尝试使用 JOIN 和 CASE。以下是查询:
SELECT b.month,
(CASE WHEN p.travel_mode=train then b.amount end)train,
(CASE WHEN p.travel_mode=bus then b.amount end)bus,
(CASE WHEN p.travel_mode=air then b.amount end)air
FROM
(SELECT to_char(date_,month) as month, travel_mode, sum(bookings) as amount
from bookings as b
join providers as p
on b.provider_id=p.provider_id
group by b.month, p.travel_mode)
group by b.month;
但是我收到一条错误消息:
subquery in FROM must have an alias LINE 6:
当我添加别名时,它会抛出一条错误消息:
column p.travel_mode must appear in the GROUP BY clause or be used in an aggregate function LINE 2:
最后的结果应该是这样的
Month Air Bus Train
01 Amount(air) Amount(Bus) Amount(train)
我感觉这是某个地方的小错误,但我根本无法弄清楚。
P.S。我不得不删除问题中的所有引号,因为它不允许我 post 这个。但是在实际查询中会处理这些问题。
您必须按照错误消息所述命名子查询:
SELECT b.month,
(CASE WHEN p.travel_mode=train then b.amount end)train,
(CASE WHEN p.travel_mode=bus then b.amount end)bus,
(CASE WHEN p.travel_mode=air then b.amount end)air
FROM
(SELECT to_char(date_,month) as month, travel_mode, sum(bookings) as amount
from bookings as b
join providers as p
on b.provider_id=p.provider_id
group by b.month, p.travel_mode)
**as foo** group by b.month;
移除星号使其生效。
多个问题。缺少的 table 别名只是其中之一。此查询应该有效:
SELECT month
, sum(CASE WHEN travel_mode = 'train' THEN amount END) AS train
, sum(CASE WHEN travel_mode = 'bus' THEN amount END) AS bus
, sum(CASE WHEN travel_mode = 'air' THEN amount END) AS air
FROM (
SELECT to_char(timestamp, 'MM') AS month, travel_mode, sum(bookings) AS amount
FROM bookings b
JOIN providers p USING (provider_id)
GROUP BY month, p.travel_mode
) sub
GROUP BY month;
字符串文字缺少单引号。 (您似乎已经删除了那些在错误印象下您无法 post 引用的内容。)
缺少子查询的 table 别名 - 正如第一条错误消息所说。
在外部查询中,子查询中基础 table 的 table 名称(或别名)不可见。只有子查询的 table 别名是。因为只有 一个 子查询,所以根本不需要 table 限定。
month
是输出列名称(不在基础 table 中),因此 table 限定条件b.month
也是错误的。您似乎想要几个月的两位数。使用 template pattern 'MM' 而不是 'month' 和
to_char()
.外部查询中的聚合无法正常工作 - 就像您的第二条错误消息所说的那样。您必须将外部
CASE
表达式包装在聚合函数中。在这种情况下,您还不如使用min()
或max()
,因为在子查询之后永远不会超过一行。仍然不清楚
date_
的来源?你是说timestamp
? (这不是一个好的标识符)。
但是你不需要子查询开始,可以简化为:
SELECT to_char(timestamp, 'MM') AS month
, sum(CASE WHEN p.travel_mode = 'train' THEN b.bookings END) AS train
, sum(CASE WHEN p.travel_mode = 'bus' THEN b.bookings END) AS bus
, sum(CASE WHEN p.travel_mode = 'air' THEN b.bookings END) AS air
FROM bookings b
JOIN providers p USING (provider_id)
GROUP BY 1;
为了获得最佳性能,您仍应使用 crosstab()
,但:
- PostgreSQL Crosstab Query