Агрегирование набора результатов для каждого набора данных - PullRequest
0 голосов
/ 17 сентября 2018

У меня есть список наций.Каждое короткое сокращение (short) соответствует 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

Мой код выглядит следующим образом

Часть 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 голосов
/ 17 сентября 2018

Лучшее решение - использовать наборы группировки, стандартную функцию 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
0 голосов
/ 17 сентября 2018

Отказ от ответственности : это решение для PostgreSQL версий 9.0-9.4.Для Postgres 9,5 или выше я бы выбрал решение GROUPING SETS @ LaurenzAlbe


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.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 yoты не добавляешь строку.Если это ваше намерение, то указанная выше скрипта db <> показывает вам решение:

  1. Добавление счетчика строк для каждой оконной рамы в предложение WITH
  2. Фильтр UNIONподзапрос для всех стран с row_count > 1
0 голосов
/ 17 сентября 2018

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;

Обратите внимание, что счет для запроса сгруппирован покороткое имя не должно быть суммой подсчетов, другой запрос возвращает.Это из-за четкого подсчета.Если для студента существует несколько разных длинных имен с одним коротким именем, они учитываются в каждой группе длинного имени, но только один раз в группе для короткого имени.

...