如何在 Postgresql 交叉表中获取动态列数

Posted

技术标签:

【中文标题】如何在 Postgresql 交叉表中获取动态列数【英文标题】:How to get dynamic number of columns in Postgresql crosstab 【发布时间】:2018-03-14 06:44:36 【问题描述】:

我是 postgresql 交叉表函数的新手,并且在 SO 上尝试了一些解决方案,但仍然卡住了。所以基本上我有一个查询会产生如下输出:

|student_name|subject_name|marks|
|------------|------------|-----|
|John Doe    |ENGLISH     |65   |
|John Doe    |MATHEMATICS |72   |
|Mary Jane   |ENGLISH     |74   |
|Mary Jane   |MATHEMATICS |70   |
|------------|------------|-----|

我使用交叉表的目标是:

|student_name| ENGLISH | MATHEMATICS |
|------------|---------|-------------|
|John Doe    | 65      | 72          |
|Mary Jane   | 74      | 70          |
|------------|---------|-------------|

我返回第一个表(没有交叉表)的查询是:

SELECT student_name, subject_name, sum(marks) as marks FROM (
    SELECT student_id, student_name, class_name, exam_type, subject_name, total_mark as marks, total_grade_weight as out_of, percentage, grade, sort_order
    FROM(
        SELECT  student_id, student_name, class_name, exam_type, subject_name, total_mark, total_grade_weight, ceil(total_mark::float/total_grade_weight::float*100) as percentage,
            (select grade from app.grading where (total_mark::float/total_grade_weight::float)*100 between min_mark and max_mark) as grade, sort_order
        FROM (
            SELECT --big query with lots of JOINS
        ) q ORDER BY sort_order
    )v GROUP BY v.student_id, v.student_name, v.class_name, v.exam_type, v.subject_name, v.total_mark, v.total_grade_weight, v.percentage, v.grade, v.sort_order
    ORDER BY student_name ASC, sort_order ASC
    )a
    GROUP BY student_name, subject_name
ORDER BY student_name

对于交叉表,这就是我被列卡住的地方。

SELECT * FROM 
crosstab(' //the query above here ',
          $$VALUES ('MATHEMATICS'::text), ('marks')$$
        ) AS ct 
(student_name text, subject_name character varying, marks numeric);

如果我如上所示运行它,这就是我最终得到的结果:

|student_name|subject_name|marks|
|------------|------------|-----|
|John Doe    | 65         |     |
|Mary Jane   | 74         |     |
|____________|____________|_____|

正如上面所说的subject_name 而不是ENGLISHMATHEMATICS。显然,现在我看到我不需要 marks 列,但我怎样才能让它将所有主题名称作为列名?他们可能是两个,他们可能是 12。

【问题讨论】:

【参考方案1】:

已解决,但我更喜欢动态得多的解决方案。我替换了这个;

$$VALUES ('MATHEMATICS'::text), ('marks')$$ 用这个;

'SELECT subject_name FROM app.subjects WHERE ... ORDER BY ...' 我的解决方案的缺点是最后一部分更改为

(student_name text, english bigint, mathematics bigint, physics bigint, biology bigint, chemistry bigint, history bigint, ...);

也就是说,我必须手动列出所有主题,并且完全按照它们从上面的选择中列出的顺序。我觉得这不是很方便,但它确实有效。

【讨论】:

以上是关于如何在 Postgresql 交叉表中获取动态列数的主要内容,如果未能解决你的问题,请参考以下文章

Postgresql从具有不同列数的2个表中选择多条记录

如何在工作表中动态创建具有列数的数组,以删除多列中的重复项

PostgreSQL 动态列数结果

如何在函数中返回动态列数?

动态数据透视,postgresql中的交叉表

具有动态列名和多个输入列的 PostgreSQL 交叉表