#sql #postgresql #date #insert
Вопрос:
У меня есть SQL-запрос, который генерирует несколько строк за каждый час с информацией о рынке (по одной строке на рынок), например, накопленное количество уникальных клиентов на тот момент из таблицы, которая выглядит следующим образом, за которой следует запрос:
organization_id | транзакция_id | транзакция_date_time | Торговая площадка |
---|---|---|---|
6789 | 80031 | 2021-06-07 15:33 | 3 |
6789 | 80032 | 2021-06-07 15:34 | 3 |
6789 | 80033 | 2021-06-07 15:44 | 3 |
6789 | 80034 | 2021-06-07 15:45 | 3 |
1234 | 80035 | 2021-06-17 14:07 | 1 |
1234 | 80036 | 2021-06-17 14:07 | 1 |
4321 | 80037 | 2021-07-05 11:51 | 2 |
4321 | 80038 | 2021-07-05 11:51 | 2 |
1234 | 80039 | 2021-07-13 15:41 | 1 |
1234 | 80040 | 2021-07-14 09:41 | 1 |
1234 | 80041 | 2021-07-14 09:55 | 1 |
select
date_trunc('hour', current_timestamp) as "date_time"
,ct.country_code as market
,count(distinct ct.organization_id) acc_alltime_organizations
,count(distinct case when ct.transaction_date_time >= current_date - interval '30' day then ct.organization_id else null end) acc_1m_organizations
from customer_transactions ct
group by
"date_time"
,market
Выше приведен пример таблицы, которую я создаю (на самом деле накоплений больше, но это не должно кардинально изменить настройку) для метки current_timestamp. Мне бы хотелось, чтобы эти строки относились не только к текущей отметке времени, но и к каждому часу, например, с тех пор 2016-01-01 10:00:00
и до сих пор. Это означает, что, например, я хочу знать, что за 2018-09-09 00:00:00
месяц, предшествующий этой дате, было 10000 организаций, которые когда-либо использовали продукт, и 1000 уникальных организаций, использовавших продукт.
Столбец со всеми часами, для которых мне нужны эти строки, может быть сгенерирован следующим образом:
select count(*)
from generate_series(
(select date_trunc('hour', min(ct.transaction_date_time))
from customer_transactions ct
),
current_date,
interval '1 hour'
) as t("date_time")
)
Желаемый результат выглядит примерно так, как показано в следующей таблице:
дата и время | Торговая площадка | acc_alltime_организации | acc_1m_организации |
---|---|---|---|
2016-01-01 10:00 | 1 | 10 | 5 |
2016-01-01 10:00 | 2 | 9 | 4 |
2016-01-01 10:00 | 3 | 8 | 3 |
2016-01-01 10:00 | 4 | 7 | 2 |
2016-01-01 11:00 | 1 | 10 | 5 |
2016-01-01 11:00 | 2 | 9 | 4 |
2016-01-01 11:00 | 3 | 8 | 3 |
2016-01-01 11:00 | 4 | 7 | 2 |
2016-01-01 12:00 | 1 | 11 | 6 |
2016-01-01 12:00 | 2 | 10 | 5 |
2016-01-01 12:00 | 3 | 9 | 4 |
2016-01-01 12:00 | 4 | 8 | 3 |
… | … | … | … |
Поэтому мои мысли состояли в том, чтобы зациклиться на часах, сгенерированных с помощью приведенного выше фрагмента кода, и заменить current_date в первом фрагменте кода переменной даты, которую можно зациклить, и вставить в новую таблицу строку на рынок в час, но я застрял на том, как это реализовать.
Если есть другой метод, кроме зацикливания, который предпочтительнее, пожалуйста, также дайте мне знать :). Помощь в этом была бы очень признательна!
Комментарии:
1. . . . Пожалуйста, предоставьте примерные данные и желаемые результаты. Ваш первый запрос синтаксически неверен (я думаю , что в нем просто отсутствует a
group by
, но неясно, чего еще может не хватать).2. Вы правы, я удалил слишком много из исходного запроса, я обязательно исправлю его. Я также добавлю немного примеров данных, столько, сколько смогу :).
Ответ №1:
Если это ваш первоначальный запрос:
select date_trunc('hour', current_timestamp) as date_time,
ct.country_code as market,
count(distinct ct.organization_id) as acc_alltime_organizations,
count(distinct case when ct.transaction_date_time >= current_date - interval '30' day then ct.organization_id end) as acc_1m_organizations
from customer_transactions ct
group by ct.country_code;
Затем вы можете изменить его в течение нескольких часов, используя:
select h.date_time,
t.country_code as market,
count(distinct ct.organization_id) as acc_alltime_organizations,
count(distinct case when ct.transaction_date_time >= h.date_time - interval '30' day then ct.organization_id end) as acc_1m_organizations
from (select generate_series(min(ct.transaction_date_time), current_date, interval '1 hour') as date_time
from customer_transactions ct
) h left join
customer_transactions ct
on ct.transaction_date_time <= h.date_time
group by h.date_time, ct.country_code
Возможно, существуют более эффективные способы расчета того, что вы хотите, но это отвечает на заданный вами вопрос. Возможно, вам захочется задать новый вопрос с образцами данных, желаемыми результатами и четким объяснением нужной вам логики.
Комментарии:
1. Спасибо вам за ваш ответ. Я добавил еще немного информации о образцах набора данных, который у меня есть, и желаемом результате. Я попытался запустить ваш сценарий, и, к сожалению, его запуск занимает очень много времени, даже если я запускал его только в течение последних 3 часов (более 500 секунд для этого и подсчета) на меньшей выборке набора данных для разработки. Если бы вы могли дать несколько советов по более эффективному решению, это было бы здорово. Я не возражаю против логики, пока я получаю результат (несколько) эффективно. Спасибо!