Postgres - 将行转置为列

dac*_*ogy 38 sql database postgresql transpose crosstab

我有下表,它为每个用户提供了多个电子邮件地址.

在此输入图像描述

我需要将其展平为用户查询的列.根据创建日期向我提供"最新"3个电子邮件地址.

user.name | user.id | email1          | email2           | email3**

Mary      | 123     | mary@gmail.com  | mary@yahoo.co.uk | mary@test.com

Joe       | 345     | joe@gmail.com   | [NULL]           | [NULL]
Run Code Online (Sandbox Code Playgroud)

Erw*_*ter 48

使用crosstab()tablefunc模块.

SELECT * FROM crosstab(
   $$SELECT user_id, user_name, rn, email_address
     FROM  (
        SELECT u.user_id, u.user_name, e.email_address
             , row_number() OVER (PARTITION BY u.user_id
                            ORDER BY e.creation_date DESC NULLS LAST) AS rn
        FROM   usr u
        LEFT   JOIN email_tbl e USING (user_id)
        ) sub
     WHERE  rn < 4
     ORDER  BY user_id
   $$
  , 'VALUES (1),(2),(3)'
   ) AS t (user_id int, user_name text, email1 text, email2 text, email3 text);
Run Code Online (Sandbox Code Playgroud)

我使用美元引用作为第一个参数,没有特殊含义.如果你必须在查询字符串中转义单引号,这是一种常见的情况,这很方便:

详细说明和说明如下:

特别是对于"额外列":

这里的特殊困难是:

  • 缺少关键名称.
    - >我们用row_number()子查询替换.

  • 电子邮件数量不一.
    - >我们限制到最大值.三个在外部SELECT
    并使用crosstab()两个参数,提供可能的键列表.

注意NULLS LASTORDER BY.

  • @MarcelloGrechiLins:Redshift是一个基于Postgres 8.0.2的分支和[不支持的Postgres功能列表](http://docs.aws.amazon.com/redshift/latest/dg/c_unsupported-postgresql-features.html)长得很久.BTW,[它是*PostgreSQL*或*Postgres*,从不*"Postgre"*](https://wiki.postgresql.org/wiki/Identity_Guidelines).这就像说*"Redshif"*. (6认同)
  • @ErwinBrandstetter我知道,但是由于Redshift使用"Postgre Compliant"驱动程序,大多数Redshift用户寻找他们问题的答案而不是搜索"PostgreSQL",因为社区规模更大,并且有机会找到Redshift问题的答案, Postgre帖子更高:)希望这是有道理的 (4认同)
  • 完美,谢谢你.完全符合我的需要.这个查询有点超出我的想法,但帮助我学习和理解了很多. (2认同)
  • 对于那些少数人的疑惑.不,这不适用于AWS Redshift. (2认同)
  • @MarcelloGrechiLins:此问答适用于 Postgres,而不是 Redshift。 (2认同)

Han*_*olm 16

如果其他人发现了这个问题,并且需要一个动态解决方案,你有一个未定义的列数要转置,而不是3,你可以在这里找到一个很好的解决方案:https://github.com/jumpstarter-io/ colpivot