为每组数据汇总一组结果

时间:2018-09-17 12:40:31

标签: sql postgresql grouping postgresql-9.3

我有国家名单。每个简短缩写(short)都对应一个国家/地区,但是人们喜欢输入除国家/地区名称之外的其他变量,该国家/地区名称以下面的列表结尾

输出

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

我的代码如下

第1部分

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 )

第2部分

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

3 个答案:

答案 0 :(得分:2)

最好的解决方案是使用分组集,这是一种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

答案 1 :(得分:2)

免责声明:这是PostgreSQL 9.0-9.4版的解决方案。对于 Postgres 9.5 或更高版本,我会使用@LaurenzAlbe的GROUPING SETS解决方案


demo: db<>fiddle

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

A:WITH子句使查询更具可读性,因为您无需两次编写相同的子查询。

B:窗口函数(https://www.postgresql.org/docs/current/static/tutorial-window.htmlSUM汇总给定帧(此处为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 <> fiddle链接将为您显示解决方案:

  1. 将每个窗口框架的行计数器添加到WITH子句
  2. 使用UNION过滤所有国家的row_count > 1子查询

答案 2 :(得分:0)

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;

请注意,按短名称分组的查询的计数不得为计数的总和,其他查询将返回。那是因为数量不同。如果对于一个学生来说,有多个不同的长名和一个短名,则它们会被计入长名的每个组中,但在短名组中只会被计数一次。