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 ответов

6 просмотров

Ты хочешь развернуть часть таблички. Почитай про 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

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

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

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

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

А чем вам питонисты не угодили?😂
.
79
Язык Си можно выучить за день? По книжке ANSI C на 230 страниц
Vincent Vegan
29
Привет, запускаю werf в dind в k8s, получаю ошибку на этапе build/beforeSetup: /.werf/stapel/embedded/bin/bash: /.werf/scripts/5898bdfe5214357d3706b879cc8d3d78460fb379607cbd...
florius0
7
Dim Dim, [02.07.2024 11:07] DB 0x62 Dim Dim, [02.07.2024 11:07] DB 0x66 Dim Dim, [02.07.2024 11:07] кто пояснит что это?
Dim Dim
14
Всем привет, написал код ниже, но он выдает сегфолт, в чем причина? #include <stdio.h> #include <stdlib.h> #include <string.h> struct product { char *name; float price; };...
buzz базз
75
Ребят, а за скок можно впарить анон чат с апишкой и веб админкой ?
Eugene Неелов
15
Кстати, я тут еще с одной темой столкнулся, вот учу я C++, на таком то ресурсе, а остальные постоянно советуют практиковаться, что то писать, проекты, но как писать если вот т...
aaswq1
7
Подскажите, можно ведь комбинировать запись данных в один и тот же Stream через TFileStream и через TCompressionStream поочерёдно? Ну т.е. часть данных мне нужно сжать, часть ...
notme
4
Ещё такой вопрос. Мне необходимо хранить пароль пользователя локально. Для этого планирую использовать ini файл. Это для автозаполнения полей логин и пароль при авторизации. Е...
Евгений
19
Кстати на работу никто не хочет, слегка на Сшке подписывать? От 170к в месяц, под Москвой
Andrey Ermakov
6
Карта сайта