【问题标题】:PostgreSQL one to many pivot with crosstab带有交叉表的 PostgreSQL 一对多枢轴
【发布时间】:2016-02-17 00:34:10
【问题描述】:

我正在尝试在PostgreSQL 中构建一个一对多查询,该查询查看客户表、交易表,结果是显示客户购买了哪些产品的表。

table: customers
id
1
2
3
4
5

table: purchases
custid  product
1       software 1
1       software 2
3       software 2
3       software 3  
4       software 1
5       software 1
5       software 2
5       software 3

我想要得到的结果是:

custid  software1   software2   software3
1       TRUE        TRUE        NULL
3       NULL        TRUE        TRUE
4       TRUE        NULL        NULL
5       TRUE        TRUE        TRUE

据我所知,我需要使用crosstab(因为postgreSQL 不支持pivot),但我不确定snytax。如果输出包含行,我也可以:

custid  software1   software2   software3
2       NULL        NULL        NULL

如果以一种或另一种方式更容易做到这一点,那并不重要。

【问题讨论】:

  • 您是否喜欢 customers.id 被包括在内?还是性能更重要?
  • 最好将其包含在内。

标签: sql postgresql pivot crosstab


【解决方案1】:

忽略没有购买任何东西的客户,因为这样会更短更快:

SELECT * FROM crosstab(
    'SELECT custid, product, true FROM purchases ORDER BY 1, 2'    
  , $$VALUES ('software 1'::text), ('software 2'), ('software 3')$$)
AS ct (custid int, software1 bool, software2 bool, software3 bool);

详情:

这里有一个小困难:您需要在查询中添加 boolean 值,因为它不在表中。

【讨论】:

  • 这些值应该是('software 1'::text), ('software 2'::text), ('software 3'::text)吗?
  • @fauxgt4:你可以这样做,但这不是必须的。 VALUES 表达式中的数据类型由第一行确定。其他行被强制转换为相同的类型。
【解决方案2】:

我对交叉表不熟悉,但你可以使用 group by 子句和这样的 case 表达式(仅当只有这 3 个软件,如果无限,则此解决方案不好):

SELECT t.id,
       max(case when s.product = 'software 1' then true end) as software1,
       max(case when s.product = 'software 2' then true end) as software2,
       max(case when s.product = 'software 3' then true end) as software3
FROM customers t
LEFT OUTER JOIN purchases s ON(t.id = s.custid)
GROUP BY t.id

这还将包括缺少 ID 的行。

【讨论】:

  • 这行得通(除了 max 不能在布尔值上工作,只是切换到整数 1,但效果很好)。这样做的缺点是处理时间。即使对输出有一些限制,它仍然有点长,但确实得到了我需要的结果。对于完整的查询,我将安排一夜之间。
猜你喜欢
  • 1970-01-01
  • 2021-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-19
  • 2021-07-16
相关资源
最近更新 更多