我有一份国家名单。每个简短的缩写(短)对应1个国家,但是人们喜欢输入除了国家名称之外的其他变量,这些变量以下面的列表结束
short nation Students
A A 604
A Austria 6707
A Österreich 3400
AFG Afg 18
AFG Afghanistan 1991
AGL Angola 16
AGN Guinea 2
AL Al 5
AL Albanien 61
ARM Arm 6
ARM Armenien 87
因此,您可以看到计算每个国家/地区的学生总数可以得出2或3个结果。很明显,如果有可能计算出如下所示的每个短语的总和,我就会想到这个问题
short nation Students
A A 604
A Austria 6707
A Österreich 3400
A 10711
AFG Afg 18
AFG Afghanistan 1991
AFG 2009
AGL Angola 16
AGN Guinea 2
AL Al 5
AL Albanien 61
AL 66
ARM Arm 6
ARM Armenien 87
ARM 93
我的代码如下
with natctf as (
SELECT short,
nation,
cast(Studentcount as varchar(6)) as Studentcount
FROM (
SELECT ctf.shorttext as short, ctf.longtext as nation,
count(distinct s.studentid) as Studentcount
from students s
join pupil p on p.id = s.pupilid
join pupilnation pn on pn.pupilid = p.id
join country ctf on ctf.id = pn.coutnryid
Group by ctf.shorttext,ctf.longtext
Order by ctf.shorttext
) t )
SELECT short, initcap(nation), Studentcount
FROM natctf
UNION ALL
SELECT null as short,
cast(count(nation) as varchar(3)) ||' Nations',
cast(SUM(cast(Studentcount as bigint)) as varchar(10)) ||' Students'
FROM natctf
免责声明:这是PostgreSQL版本9.0-9.4的解决方案。对于Postgres 9.5或更高版本,我会使用@LaurenzAlbe的GROUPING SETS
解决方案
WITH count_nations AS ( -- A
SELECT
*,
sum(students) OVER (PARTITION BY short) as total -- B
FROM nations
)
SELECT short, name, students FROM count_nations -- C
UNION -- E
SELECT short, NULL, total FROM count_nations -- D
ORDER BY
short,
name NULLS LAST, -- F
students
答:WITH
子句使查询更具可读性,因为您不需要两次编写相同的子查询。
B:窗口函数(https://www.postgresql.org/docs/current/static/tutorial-window.html)SUM
总结给定帧中的所有值(这里是short
列)。所以你将这些国家的总数作为单独的列。
子查询的结果:
short name students total
A A 604 10711
A Austria 6707 10711
A Österreich 3400 10711
AFG Afg 18 2009
AFG Afghanistan 1991 2009
AGL Angola 16 16
AGN Guinea 2 2
AL Al 5 66
AL Albanien 61 66
ARM Arm 6 93
ARM Armenien 87 93
C:选择原始栏目......
D:选择没有名称的新列...
E:UNION
两个结果。 UNION
使结果与众不同,因此每个国家只能获得一排。 (UNION ALL
不会这样做)
F:订购结果。对于国家行,NULL
值应该是最后一行。
结果:
short name students
A A 604
A Austria 6707
A Österreich 3400
A 10711
AFG Afg 18
AFG Afghanistan 1991
AFG 2009
AGL Angola 16
AGL 16
AGN Guinea 2
AGN 2
AL Al 5
AL Albanien 61
AL 66
ARM Arm 6
ARM Armenien 87
ARM 93
在您的示例中,仅为具有多行的国家/地区添加额外行。例如,对于AGN
,您不添加行。如果这是您的意图,上面链接的db <>小提示符将显示解决方案:
WITH
子句中UNION
过滤所有国家的row_count > 1
子查询最好的解决方案是使用分组集,这是一个适用于您的用例的SQL标准功能:
SELECT ctf.shorttext as short,
ctf.longtext as nation,
count(...)
FROM country AS ctf JOIN ...
GROUP BY GROUPING SETS ((ctf.shorttext, ctf.longtext), (ctf.shorttext))
ORDER BY ctf.shorttext, ctf.longtext
UNION ALL
一个查询,你GROUP BY
短和长的名称和另一个你只用短名称组。
SELECT x.short,
x.nation,
x.studentcount
FROM (SELECT ctf.shorttext short,
ctf.longtext nation,
count(DISTINCT s.studentid) studentcount
FROM students s
INNER JOIN pupil p
ON p.id = s.pupilid
INNER JOIN pupilnation pn
ON pn.pupilid = p.id
INNER JOIN country ctf
ON ctf.id = pn.coutnryid
GROUP BY ctf.shorttext,
ctf.longtext
UNION ALL
SELECT ctf.shorttext short,
NULL nation,
count(DISTINCT s.studentid) studentcount
FROM students s
INNER JOIN pupil p
ON p.id = s.pupilid
INNER JOIN pupilnation pn
ON pn.pupilid = p.id
INNER JOIN country ctf
ON ctf.id = pn.coutnryid
GROUP BY ctf.shorttext) x
ORDER BY x.short,
x.nation NULLS LAST;
请注意,按短名称分组的查询计数不能是计数的总和,另一个查询将返回。这是因为非常重要。如果学生有几个不同的长名称和一个短名称,他们会在长名称的每个组中计算,但在短名称的组中只计算一次。