Сводная таблица без кросс-таблицы / tablefunc - PullRequest
0 голосов
/ 07 февраля 2020

У меня есть такая таблица

INPUT

id    author    size    file_ext
--------------------------------
1     a         13661   python
1     a         13513   cpp
1     a         1211    non-code
2     b         1019    python
2     b         6881    cpp
2     b         1525    python
2     b         1208    non-code
3     c         1039    python 
3     c         1299    cpp

Я хочу иметь возможность поворачивать эту таблицу следующим образом

OUTPUT

id    author    size    python    cpp    non-code
-------------------------------------------------
1     a         13661   1         0      0
1     a         13513   0         1      0
1     a         1211    0         0      1 
2     b         1019    1         0      0
2     b         6881    0         1      0
2     b         1525    1         0      0
2     b         1208    0         0      1
3     c         1039    1         0      0
3     c         1299    0         1      0

Все статьи, которые я могу найти в сводных таблицах онлайн, основаны на втором столбце. Моя конечная цель - получить одну запись для каждого удостоверения личности

ФИНАЛЬНЫЙ ВЫХОД

id    author    size    python    cpp    non-code
-------------------------------------------------
1     a         28385   1         1      1
2     b         10633   2         1      1
3     c         2338    1         1      0

Здесь агрегируются значения размера, python, cpp, некодовые столбцы.

Ответы [ 3 ]

2 голосов
/ 08 февраля 2020

С условным агрегированием:

select 
  id, author,
  sum(size) size,
  sum((file_ext = 'python')::int) python,
  sum((file_ext = 'cpp')::int) cpp,
  sum((file_ext = 'non-code')::int) "non-code"
from tablename
group by id, author

См. Демоверсию . Результаты:

> id | author |  size | python | cpp | non-code
> -: | :----- | ----: | -----: | --: | -------:
>  1 | a      | 28385 |      1 |   1 |        1
>  2 | b      | 10633 |      2 |   1 |        1
>  3 | c      |  2338 |      1 |   1 |        0
0 голосов
/ 08 февраля 2020

Несмотря на то, что вы хотите избежать функции crosstab(), используйте агрегатное выражение FILTER для лучшей производительности и четкого кода:

SELECT id, author
     , sum(size) AS size
     , count(*) FILTER (WHERE file_ext = 'python')   AS python
     , count(*) FILTER (WHERE file_ext = 'cpp')      AS cpp
     , count(*) FILTER (WHERE file_ext = 'non-code') AS "non-code"
FROM   tablename
GROUP  BY id, author;

Это самый быстрый способ с использованием только агрегатных функций. См .:

Для достижения максимальной производительности crosstab() обычно быстрее, хотя в этом случае более многословно:

SELECT id, author, size
     , COALESCE(python    , 0) AS python
     , COALESCE(cpp       , 0) AS cpp
     , COALESCE("non-code", 0) AS "non-code"
FROM   crosstab(
$$
SELECT id, author
     , sum(sum(size)) OVER (PARTITION BY id) AS size
     , file_ext
     , count(*) AS ct
FROM   tablename
GROUP  BY id, author, file_ext
ORDER  BY id, author, file_ext
$$
, $$VALUES ('python'), ('cpp'), ('non-code')$$
) AS (id int, author text, size numeric
    , python int, cpp int, "non-code" int);

Тот же результат.

дБ < > скрипка здесь - с промежуточными шагами .

Подробное объяснение:

О функции окна над функцией агрегирования (sum(sum(size)) OVER (...)) см .:

Обратите внимание на небольшую разницу, если для одного и того же * 1054 должно быть несколько author *: хотя первый запрос возвращает несколько строк в этом случае, вариант crosstab() просто выбирает первого автора.

0 голосов
/ 08 февраля 2020

Вы также можете использовать расширение кросс-таблицы PostgreSQL, которое называется tablefun c. Я советую вам взглянуть на эту ссылку (приведенный там пример очень похож на желаемый результат): https://vertabelo.com/blog/creating-pivot-tables-in-postgresql-using-the-crosstab-function/

...