Добавление аггрегации в вывод запроса через UNION
От: cppguard  
Дата: 09.12.22 06:02
Оценка:
Нужно отобразить в таблице выборку из таблицы, а в последней строке указать аггрегацию по некоторым полям. Запрос выполняется из ruby, поэтому многопоточность и async/await недоступны. Первая мысль — запихнуть всё в один запрос вида
SELECT a, b, c FROM table UNION SELECT null, avg(b), max(c) FROM table


Насколько это идиоматично?
Re: Добавление аггрегации в вывод запроса через UNION
От: Dym On Россия  
Дата: 09.12.22 06:27
Оценка:
Здравствуйте, cppguard, Вы писали:

SELECT a, b, c FROM table UNION SELECT null, avg(b), max(c) FROM table

C>Насколько это идиоматично?
СУБД какая? Инструкции group by rollup/cube поддерживает?
Счастье — это Glück!
Re[2]: Добавление аггрегации в вывод запроса через UNION
От: cppguard  
Дата: 09.12.22 06:51
Оценка:
Здравствуйте, Dym On, Вы писали:

DO>СУБД какая? Инструкции group by rollup/cube поддерживает?


PostgreSQL.
Re[3]: Добавление аггрегации в вывод запроса через UNION
От: Dym On Россия  
Дата: 09.12.22 06:59
Оценка: 90 (2)
Здравствуйте, cppguard, Вы писали:

DO>>СУБД какая? Инструкции group by rollup/cube поддерживает?

C>PostgreSQL.
Раскури эту тему https://postgrespro.ru/docs/postgrespro/15/queries-table-expressions#QUERIES-GROUPING-SETS
Счастье — это Glück!
Re: Добавление аггрегации в вывод запроса через UNION
От: _ABC_  
Дата: 09.12.22 07:17
Оценка: +1
Здравствуйте, cppguard, Вы писали:

C>Нужно отобразить в таблице выборку из таблицы, а в последней строке указать аггрегацию по некоторым полям. Запрос выполняется из ruby, поэтому многопоточность и async/await недоступны. Первая мысль — запихнуть всё в один запрос вида

C>
C>SELECT a, b, c FROM table UNION SELECT null, avg(b), max(c) FROM table
C>


C>Насколько это идиоматично?

В целом, ИМХО, нормально, только я бы union на union all заменил.
Более правильно с логической точки зрения и быстрее.

Rollup не подойдёт, т.к. в общем случае он произведёт не такой же результат, что запрос выше.
"Потерял дар речи за зря"(с).
Re[2]: Добавление аггрегации в вывод запроса через UNION
От: cppguard  
Дата: 10.12.22 04:17
Оценка:
Здравствуйте, _ABC_, Вы писали:

_AB>Rollup не подойдёт, т.к. в общем случае он произведёт не такой же результат, что запрос выше.


А в чём может быть разница? Если в порядке строк, до где-то пишут, что даже UNION ALL не обязан добавлять строку второго запроса имеено в конец выборки, а может поместить её в произвольном месте. Но ORDER BY решает проблему упорядочевания в обоих случаях.
Re[3]: Добавление аггрегации в вывод запроса через UNION
От: Dym On Россия  
Дата: 10.12.22 05:44
Оценка:
Здравствуйте, cppguard, Вы писали:

C>А в чём может быть разница?

В общем случае rollup собирает подытоги по указанным полям, это добавляет гибкости к запросу, но для предельного случая потребует некоторой подстройки.
Счастье — это Glück!
Re[4]: Добавление аггрегации в вывод запроса через UNION
От: cppguard  
Дата: 10.12.22 05:55
Оценка:
Здравствуйте, Dym On, Вы писали:

C>>А в чём может быть разница?

DO>В общем случае rollup собирает подытоги по указанным полям, это добавляет гибкости к запросу, но для предельного случая потребует некоторой подстройки.

Я если взять конкретный пример, то в чём разница?

SELECT id, qty, price FROM table
UNION ALL
SELECT null, sum(qty), avg(price) FROM TABLE


SELECT id, sum(qty), avg(price) FROM TABLE GROUP BY id WITH ROLLUP
Re[3]: Добавление аггрегации в вывод запроса через UNION
От: Sinclair Россия https://github.com/evilguest/
Дата: 10.12.22 07:40
Оценка: +1
Здравствуйте, cppguard, Вы писали:
C>А в чём может быть разница?
В производительности. UNION означает "без дубликатов", поэтому сервер обязан хранить все строки первого аргумента вплоть до порождения строки второго, а потом проверить, не совпадает ли она с какой-то из первых строк.
Запрос с UNION эквивалентен вот такому:
SELECT a, b, c 
FROM (
      SELECT a, b, c FROM table 
        UNION ALL
      SELECT null, avg(b), max(c) FROM table
     )
GROUP BY a, b, c

Очень немногие движки способны такое оптимизировать, даже если a — PK NOT NULL.
Ещё один побочный эффект — если (a, b, c) неуникальны (что на практике встречается исчезающе редко), то запрос с UNION ещё и вернёт меньше строк, чем с UNION ALL.

C>Если в порядке строк, до где-то пишут, что даже UNION ALL не обязан добавлять строку второго запроса имеено в конец выборки, а может поместить её в произвольном месте.

Без ORDER BY порядок строк запроса не определён, так что СУБД вольна отдавать данные так, как ей удобно.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: Добавление аггрегации в вывод запроса через UNION
От: Sinclair Россия https://github.com/evilguest/
Дата: 10.12.22 07:48
Оценка: 24 (1)
Здравствуйте, Dym On, Вы писали:

DO>Здравствуйте, cppguard, Вы писали:


DO>>>СУБД какая? Инструкции group by rollup/cube поддерживает?

C>>PostgreSQL.
DO>Раскури эту тему https://postgrespro.ru/docs/postgrespro/15/queries-table-expressions#QUERIES-GROUPING-SETS
Совершенно верно.
SELECT a, avg(b), sum(c) FROM table group by grouping sets ((a, b, c), ())

должно вернуть то, что нужно.
https://www.db-fiddle.com/f/dGQVZZiEny1Y66NjCW6dXX/0
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[5]: Добавление аггрегации в вывод запроса через UNION
От: _ABC_  
Дата: 10.12.22 21:46
Оценка: +1
Здравствуйте, cppguard, Вы писали:

C>Я если взять конкретный пример, то в чём разница?

C>
C>SELECT id, qty, price FROM table
C>UNION ALL
C>SELECT null, sum(qty), avg(price) FROM TABLE
C>


C>
C>SELECT id, sum(qty), avg(price) FROM TABLE GROUP BY id WITH ROLLUP
C>


У ТС не id первой колонкой, а 'a', что будет, если 'a' не уникальная? Мы же не конкретный пример рассматриваем, а весьма общий.

C>Если в порядке строк, до где-то пишут

Никогда не полагайся на порядок строк, возвращаемый по умолчанию. Это стандарт SQL.
Если нужен конкретный порядок, он задаётся order by или, допустим, на клиенте.
То, что сегодня работает неявно на конкретной версии, через 10 лет может не работать точно так же неявно на другой. А через 10 лет ты уже забудешь о том, почему ты это делал и как.
"Потерял дар речи за зря"(с).
Re[4]: Добавление аггрегации в вывод запроса через UNION
От: VladiCh  
Дата: 19.04.23 06:04
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, cppguard, Вы писали:

C>>А в чём может быть разница?
S>В производительности. UNION означает "без дубликатов", поэтому сервер обязан хранить все строки первого аргумента вплоть до порождения строки второго, а потом проверить, не совпадает ли она с какой-то из первых строк.
S>Запрос с UNION эквивалентен вот такому:
S>
S>SELECT a, b, c 
S>FROM (
S>      SELECT a, b, c FROM table 
S>        UNION ALL
S>      SELECT null, avg(b), max(c) FROM table
S>     )
S>GROUP BY a, b, c
S>

S>Очень немногие движки способны такое оптимизировать, даже если a — PK NOT NULL.
S>Ещё один побочный эффект — если (a, b, c) неуникальны (что на практике встречается исчезающе редко), то запрос с UNION ещё и вернёт меньше строк, чем с UNION ALL.

C>>Если в порядке строк, до где-то пишут, что даже UNION ALL не обязан добавлять строку второго запроса имеено в конец выборки, а может поместить её в произвольном месте.

S>Без ORDER BY порядок строк запроса не определён, так что СУБД вольна отдавать данные так, как ей удобно.

В общем случае (и по стандарту) это так, но в конкретных имплементациях (в том же постгресе) порядок можно зафиксировать.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.