如何在 Postgresql 交叉表中获取动态列数
How to get dynamic number of columns in Postgresql crosstab
我是 postgresql crosstab 函数的新手,并且已经在 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 |
|------------|---------|-------------|
我的查询 returns 第一个 table(没有交叉表)是:
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
而不是 ENGLISH
或 MATHEMATICS
。显然,现在我看到我不需要 marks
列,但是我怎样才能让它将所有主题名称作为列名称?他们可能是两个,也可能是 12 个。
已解决,但我更希望有一个更加动态的解决方案。我替换了这个;
$$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, ...);
也就是说,我必须手动列出所有主题,并且完全按照上面列出的顺序 select。我觉得这不是很方便,但它确实有效。
我是 postgresql crosstab 函数的新手,并且已经在 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 |
|------------|---------|-------------|
我的查询 returns 第一个 table(没有交叉表)是:
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
而不是 ENGLISH
或 MATHEMATICS
。显然,现在我看到我不需要 marks
列,但是我怎样才能让它将所有主题名称作为列名称?他们可能是两个,也可能是 12 个。
已解决,但我更希望有一个更加动态的解决方案。我替换了这个;
$$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, ...);
也就是说,我必须手动列出所有主题,并且完全按照上面列出的顺序 select。我觉得这不是很方便,但它确实有效。