第 2 部分:如何在不实际旋转的情况下获取基于分区的查询的总和
Part 2: how to get the Sum of a partition based query without actually pivoting
所以因为我没有最新版本的 Postgresql(我有 Postgresql 9.3),所以我不可能想出一个类似于 pivot 函数的函数来计算一个特定字段的总值。
你可以点击下面的link来使用我创建的一个问题作为参考,它们在代码上相似但在需求方面有所不同但是有第二个查询使用数组并且也产生确切的同样的结果。
我目前得到以下结果
我想要这些结果
下面我有一个查询 return让我知道学生在 3 个不同的列中说的语言......我的问题是我无法想出一个解决方案可能 return 我有多少学生说 1 语言 1,有多少学生说语言 2,有多少学生说语言 3
with t as (
SELECT s.studentnumber as studentnr, p.firstname AS name,
sl.gradenumber as gradenumber, l.text as language,
dense_rank() over (partition by s.studentnumber,
p.firstname, sl.gradenumber order by l.text) as seqnum
FROM student s JOIN
pupil p
ON p.id = s.pupilid JOIN
pupillanguage pl
ON pl.pupilid = p.id JOIN
language l
ON l.id = pl.languageid JOIN
schoollevel sl
ON sl.id = p.schoollevelid
)
select studentnr, name, gradenumber,
max(case when seqnum = 1 then language end) as language_1,
max(case when seqnum = 2 then language end) as language_2,
max(case when seqnum = 3 then language end) as language_3
from t
group by studentnr, name, gradenumber;
我问这个问题是因为如果没有办法做到这一点,那么如果不可能,我就没有必要进一步研究它。
partition 和 denserank 的整个概念对我来说是相对较新的,我不确定它们产生进一步结果的程度和能力。
使用你已有的解决方案(两者之一,出于显而易见的原因我更喜欢数组解决方案),将其放入 CTE,然后使用 UNION 计算总数:
with students as (
select studentnr,
name,
gradenumber,
languages[1] as language_1,
languages[2] as language_2,
languages[3] as language_3,
languages[4] as language_4,
languages[5] as language_5
FROM (
SELECT s.studentnumber as studentnr,
p.firstname AS name,
sl.gradenumber as gradenumber,
array_agg(DISTINCT l.text) as languages
FROM student s
JOIN pupil p ON p.id = s.pupilid
JOIN pupillanguage pl on pl.pupilid = p.id
JOIN language l on l.id = pl.languageid
JOIN schoollevel sl ON sl.id = p.schoollevelid
GROUP BY s.studentnumber, p.firstname
) t
)
select *
from students
union all
select null as studentnr,
null as name,
null as gradenumber,
count(language_1)::text,
count(language_2)::text,
count(language_3)::text,
count(language_4)::text,
count(language_5)::text
from students;
count()
等聚合函数会忽略 NULL
值,因此它只会对存在某种语言的行进行计数。
UNION 查询中所有列的数据类型必须匹配,因此如果第一个查询将该列定义为文本 (或变种)。这就是为什么 count()
的结果需要转换为 text
第二个查询中的列别名并不是必需的,但我添加它们是为了说明列列表必须如何匹配
所以因为我没有最新版本的 Postgresql(我有 Postgresql 9.3),所以我不可能想出一个类似于 pivot 函数的函数来计算一个特定字段的总值。
你可以点击下面的link来使用我创建的一个问题作为参考,它们在代码上相似但在需求方面有所不同但是有第二个查询使用数组并且也产生确切的同样的结果。
我目前得到以下结果
我想要这些结果
下面我有一个查询 return让我知道学生在 3 个不同的列中说的语言......我的问题是我无法想出一个解决方案可能 return 我有多少学生说 1 语言 1,有多少学生说语言 2,有多少学生说语言 3
with t as (
SELECT s.studentnumber as studentnr, p.firstname AS name,
sl.gradenumber as gradenumber, l.text as language,
dense_rank() over (partition by s.studentnumber,
p.firstname, sl.gradenumber order by l.text) as seqnum
FROM student s JOIN
pupil p
ON p.id = s.pupilid JOIN
pupillanguage pl
ON pl.pupilid = p.id JOIN
language l
ON l.id = pl.languageid JOIN
schoollevel sl
ON sl.id = p.schoollevelid
)
select studentnr, name, gradenumber,
max(case when seqnum = 1 then language end) as language_1,
max(case when seqnum = 2 then language end) as language_2,
max(case when seqnum = 3 then language end) as language_3
from t
group by studentnr, name, gradenumber;
我问这个问题是因为如果没有办法做到这一点,那么如果不可能,我就没有必要进一步研究它。
partition 和 denserank 的整个概念对我来说是相对较新的,我不确定它们产生进一步结果的程度和能力。
使用你已有的解决方案(两者之一,出于显而易见的原因我更喜欢数组解决方案),将其放入 CTE,然后使用 UNION 计算总数:
with students as (
select studentnr,
name,
gradenumber,
languages[1] as language_1,
languages[2] as language_2,
languages[3] as language_3,
languages[4] as language_4,
languages[5] as language_5
FROM (
SELECT s.studentnumber as studentnr,
p.firstname AS name,
sl.gradenumber as gradenumber,
array_agg(DISTINCT l.text) as languages
FROM student s
JOIN pupil p ON p.id = s.pupilid
JOIN pupillanguage pl on pl.pupilid = p.id
JOIN language l on l.id = pl.languageid
JOIN schoollevel sl ON sl.id = p.schoollevelid
GROUP BY s.studentnumber, p.firstname
) t
)
select *
from students
union all
select null as studentnr,
null as name,
null as gradenumber,
count(language_1)::text,
count(language_2)::text,
count(language_3)::text,
count(language_4)::text,
count(language_5)::text
from students;
count()
等聚合函数会忽略 NULL
值,因此它只会对存在某种语言的行进行计数。
UNION 查询中所有列的数据类型必须匹配,因此如果第一个查询将该列定义为文本 (或变种)。这就是为什么 count()
的结果需要转换为 text
第二个查询中的列别名并不是必需的,但我添加它们是为了说明列列表必须如何匹配