【问题标题】:Postgres - rows to columnsPostgres - 行到列
【发布时间】:2021-03-23 06:50:31
【问题描述】:

我有什么

查询:

SELECT u.firstname,u.lastname, u.institution as department, u.department as company, c.shortname,  
to_char(to_timestamp(p.timecompleted)::date,'YYYY-MM-DD') AS completed
FROM mdl_course_completions AS p
JOIN mdl_course AS c ON p.course = c.id
JOIN mdl_user AS u ON p.userid = u.id
WHERE c.enablecompletion = 1 AND u.firstname is NOT NULL AND p.timecompleted is NOT NULL
ORDER BY u.firstname

结果:

firstname   lastname   department   company   course    completed
u1          u1         x            x          c1        date
u1          u1         x            x          c2        date

我需要什么

我需要能够将课程传输到列。导致类似这样的事情:

firstname   lastname   department   company   c1    c2
u1          u1         x            x         date  date
u2          u2         x            x         date  date   

我尝试过使用交叉表,但我对 SQL 的熟练程度不够。有人可以帮忙吗?

EDIT:课程数量在数百个,所以它需要是动态的。

(另外:英语不是我的母语,如有不明之处请见谅)。

【问题讨论】:

标签: sql postgresql pivot


【解决方案1】:

这不是您要求的,但可能对您有用。最后一列是一个数组,其结构为:{'course_name: course_completed', ...}。

SELECT u.firstname,u.lastname, u.institution as department, u.department as company
    array_agg(c.shortname || ': ' || to_char(to_timestamp(p.timecompleted)::date,'YYYY-MM-DD')) AS courses_completed
FROM mdl_course_completions AS p
JOIN mdl_course AS c ON p.course = c.id
JOIN mdl_user AS u ON p.userid = u.id
WHERE c.enablecompletion = 1 AND u.firstname is NOT NULL AND p.timecompleted is NOT NULL
GROUP BY u.firstname,u.lastname, u.institution, u.department
ORDER BY u.firstname

输出将是:

firstname   lastname   department   company   courses_completed
u1          u1         x            x         {"c1: date", "c2: date"}
u2          u2         x            x         {"c1: date", "c2: date"}

其他选项是使用交叉表功能(如您所说):Postgresql crosstab documentation。您必须安装 tablefunc 模块才能使用交叉表。阅读文档,如果您认为它对您有用,我可以帮助您编写查询(但我需要了解表结构和一些示例数据)。

【讨论】:

  • 谢谢!这非常有用,现在应该这样做:)
【解决方案2】:

您可以使用条件聚合,例如使用FILTER 子句:

SELECT
    firstname, lastname, department, company,
    MAX(completed) FILTER (WHERE course = 'c1') as c1,
    MAX(completed) FILTER (WHERE course = 'c2') as c2
FROM 
    -- <joins>
GROUP BY firstname, lastname, department, company

您需要按属于同一组的列进行分组。然后,您可以在要旋转的列上执行您喜欢的任何聚合函数。使用附加的FILTER 子句,您可以过滤所有应识别为聚合的记录。

【讨论】:

  • 感谢您的回答。然而,课程的数量有数百个,所以这将是一个非常冗长的 SQL。
  • @user2075124:没有其他办法 - 如果您需要数百列,则必须编写数百个表达式(每列一个)
  • 是的,会的。但是,使用交叉表,您还必须显式枚举列...无法动态创建列。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-09
  • 2023-03-27
  • 2013-11-18
  • 1970-01-01
  • 2014-11-16
  • 1970-01-01
相关资源
最近更新 更多