172 похожих чатов

Друзья, всем привет. Помогите с проблемой, не пойму как сделать.



А задача такая - есть в таблице комбинации по три строки с одинаковыми столбцами, кроме emission_sum и report_marker. Есть три вида report_marker, поэтому соответственно три строки. надо превратить эти три строки в одну, расширив таблицу колонками - свой emission_sum для каждого вида report_marker (emission_sum_dpnvos, emission_sum_dvos, emission_sum_pek). Как это сделать?
P.S. В запросе, в cte я убираю дубли ненужные, их я как раз с помощью этого cte вычищаю.
Я пытался делать через подзапросы, но работает оооочень долго. Даже для одного report_marker (как раз в запросе ниже). Как то можно по другому решить этот вопрос? Записей в таблице около 1.5 млн

WITH wd AS (
SELECT *
FROM
(SELECT *,
ROW_NUMBER() OVER (
PARTITION BY (pollutant_marker, onvos_code, pollutant_id, report_year)
ORDER BY sent_at DESC
) rn
FROM onvs_emissions_mass_tmp
) tmp WHERE rn = 1
)
SELECT (
SELECT emission_sum FROM wd m2
WHERE m2.onvos_code = tmp.onvos_code
AND m2.pollutant_id = tmp.pollutant_id
AND m2.report_year = tmp.report_year
AND m2.pollutant_marker = tmp.pollutant_marker
AND m2.report_marker = 'dpnvos'
) AS dpnvos
FROM wd tmp
GROUP BY pollutant_marker, onvos_code, pollutant_id, report_year

11 ответов

12 просмотров

Ты хочешь развернуть часть таблички. Почитай про pivot.

Petr
Ты хочешь развернуть часть таблички. Почитай про p...

Ну, какой пивот, о чём Вы. Пивот никогда не ускоряет никакие запросы. И вообще, его назначение — выгрузка во всякие не-реляцыонные структуры, с внешне похожэй на реляцыонную табличной организацыей. Да и то, чаще всего — это лучшэ поворачивать на клиенте, а пивот только позволяет исправить какие-то грубые ошыбки проектирования клиента.

Во-первых, https://t.me/pgsql/303899

Ilya Anfimov
Ну, какой пивот, о чём Вы. Пивот никогда не ускоря...

Ну на клиенте можно все что угодно сделать. А если говорить про скорость и оптимизации - то это очень большая тема с кучей вариантов решения. Здесь со стороны базы решить её можно и с помощью изменение структуры таблицы, навешиванием триггирров и т.д. Этот канал все таки про реляционную БД - значит для начала пробуем решать средствами самой БД.

Во-вторых, удаление "дубликатов" делается через group by, а не вот этой этажэркой с оконным функцыями.

В-третьих, это тащемта делается одним group by с предикатами where для значений вашых трёх полей. Если postgres достаточно старый или рассчитываете на поддержку зоопарка sql-движков — то можно вместо where внутри агрегатной ф-ии вставить что-то вроде min(case when report_maker='dpnvos' then emission_sum else nullend) as emission_dpnvos, и аналогично для двух других.

В-третьих, пол-миллиона значений — это не так много обычно, но жэлательно чтобы оно не пыталось это через дисксортировать. Либо work_mem ему можно временно выдать несколько гиг, либо убедиться, что есть индэкс на все поля group by , что он лезет в память (лучшэ в shared_buffers) вместе со всеми данными таблички и заставить его сделать index scan.

Александр-Орловский Автор вопроса
Ilya Anfimov
Во-вторых, удаление "дубликатов" делается через gr...

В моем случае group by для устранения дублей не применимо, по причине того что я делаю order by по колонке которая в группировке в принципе не должна участвовать, вы же видите что я это делаю в "этажерке" в секции partition by + order by

Александр-Орловский Автор вопроса
Ilya Anfimov
В-третьих, пол-миллиона значений — это не так мног...

И да, их не пол млн, их полтора. В общем спасибо всем за советы, выкрутился лаконично с помощью кейсов, отрабатывает секунд за 10, если кому то интересно решение такой проблемы WITH prp AS ( WITH wd AS ( SELECT * FROM (SELECT *, ROW_NUMBER() OVER ( PARTITION BY (pollutant_marker, onvos_code, pollutant_id, report_year) ORDER BY sent_at DESC ) rn FROM onvs_emissions_mass_tmp ) tmp WHERE rn = 1 ) SELECT id, pollutant_marker, onvos_code, pollutant_id, code, name, hazard_class, report_year, case when report_marker = 'dpnvos' then emission_sum else 0 end as dpnvos, case when report_marker = 'dvos' then emission_sum else 0 end as dvos, case when report_marker = 'pek' then emission_sum else 0 end as pek FROM wd ) SELECT ROW_NUMBER() OVER (), pollutant_marker, onvos_code, pollutant_id, code, name, hazard_class, report_year, sum(dpnvos) as emission_sum_dpnvos, sum(dvos) as emission_sum_dvos, sum(pek) as emission_sum_pek FROM prp GROUP BY pollutant_marker, onvos_code, pollutant_id, report_year, code, name, hazard_class, report_year

Александр Орловский
И да, их не пол млн, их полтора. В общем спасибо ...

а чего критерии отбора не перенести в первый запрос?

Похожие вопросы

Обсуждают сегодня

30500 за редактор? )
Владимир
47
а через ESC-код ?
Alexey Kulakov
29
Чёт не понял, я ж правильной функцией воспользовался чтобы вывести отладочную информацию? но что-то она не ловится
notme
18
Добрый день! Скажите пожалуйста, а какие программы вы бы рекомендовали написать для того, чтобы научиться управлять памятью? Можно написать динамический массив, можно связный ...
Филипп
7
У меня есть функция где происходит это: write_bit(buffer, 1); write_bit(buffer, 0); write_bit(buffer, 1); write_bit(buffer, 1); write_bit(buffer, 1); w...
~
14
Недавно Google Project Zero нашёл багу в SQLite с помощью LLM, о чём достаточно было шумно в определённых интернетах, которые сопровождались рассказами, что скоро всех "ибешни...
Alex Sherbakov
5
Ребят в СИ можно реализовать ООП?
Николай
33
Как передать управляющий символ в открытую через CreateProcess консоль? Собсна, есть процедура: procedure TRedirectThread.WriteData(Data: OEMString); var Written: Cardinal;...
Serjone
6
https://github.com/erlang/otp/blob/OTP-27.1/lib/kernel/src/logger_h_common.erl#L174 https://github.com/erlang/otp/blob/OTP-27.1/lib/kernel/src/logger_olp.erl#L76 15 лет назад...
Maksim Lapshin
20
Всем привет! Имеется функция: function IsValidChar(ch: UTF8Char): Boolean; var i: Integer; ValidChars: AnsiString; begin ValidChars := 'abcdefghijklmnopqrstuvwxyzABCDE...
Евгений
44
Карта сайта