#sql #oracle
#sql #Oracle
Вопрос:
Я пытаюсь создать таблицу, в которой отображаются рекламные акции по идентификатору группы и еженедельно. У меня есть таблица, которая показывает для каждого идентификатора группы, какая была акция и сколько недель она длилась, включая дату начала и дату окончания.
Я хочу вставить номер недели в эту таблицу, чтобы, если продвижение длилось 2 недели, я бы видел идентификатор группы в двух отдельных строках с номерами двух недель в столбце рядом с ним и дублированием всей другой информации.
Я пытался работать с функцией model, но, похоже, не могу понять, как применить ее к моим данным.
Моя текущая таблица выглядит следующим образом:
GROUP_ID PROMOTION_DESCRIPTION START_DATE END_DATE WEEKS START_YEARWEEK END_YEARWEEK MEDIA_SUPPORT
40284 Gehwol / Wartner 2e halve prijs 27-06-17 01-07-17 1 201726 201726 Radio
40315 Voordeelzakken En Dozen 26-06-17 09-07-17 2 201726 201727 Online Campagne
И я хочу, чтобы это выглядело как:
GROUP_ID WEEK PROMOTION_DESCRIPTION MEDIA_SUPPORT
40284 201706 Gehwol / Wartner 2e halve prijs Radio
40315 201726 Voordeelzakken En Dozen Online Campagne
40315 201727 Voordeelzakken En Dozen Online Campagne
Любая помощь была бы высоко оценена!
Ответ №1:
Это можно сделать, создав календарь и присоединив его к данным акции.
Приведенный ниже пример создает calendar
подфактор, который включает по одной записи для каждой недели (включая 53-ю неделю) за 2017, 2018, 2019 годы, затем присоединяется к любой promotion
записи, start_yearweek
и end_yearweek
которой пересекаются с этой календарной неделей.
WITH CALENDAR AS (
SELECT (100 * YEAR_OFFSET) WEEK_OFFSET AS CALENDAR_WEEK
FROM (
SELECT LEVEL AS WEEK_OFFSET
FROM DUAL
CONNECT BY LEVEL <= 53)
CROSS JOIN (SELECT 2016 LEVEL AS YEAR_OFFSET
FROM DUAL
CONNECT BY LEVEL <= 3))
SELECT GROUP_ID,
CALENDAR_WEEK,
PROMOTION_DESCRIPTION,
MEDIA_SUPPORT
FROM CALENDAR
INNER JOIN PROMOTION
ON CALENDAR_WEEK
BETWEEN START_YEARWEEK AND END_YEAR_WEEK;
Результат:
GROUP_ID CALENDAR_WEEK PROMOTION_DESCRIPTION MEDIA_SUPPORT
40284 201726 Gehwol / Wartner 2e halve prijs Radio
40315 201726 Voordeelzakken En Dozen Online Campagne
40315 201727 Voordeelzakken En Dozen Online Campagne
3 rows selected.
РЕДАКТИРОВАТЬ: Для создания календаря недели ISO можно использовать маску формата ‘IW’ в TO_DATE
.
В этом примере календаря генерируются недели ISO с 2014 по 2022 год:
SELECT DISTINCT TO_NUMBER(TO_CHAR((DATE '2014-01-01' LEVEL),'YYYYIW'))
AS ISO_CALENDAR_WEEK FROM DUAL
CONNECT BY (DATE '2014-01-01' LEVEL) < DATE '2023-01-01';
В примере продвижения это может быть использовано как:
WITH CALENDAR AS (
SELECT DISTINCT TO_NUMBER(TO_CHAR((DATE '2014-01-01' LEVEL),'YYYYIW'))
AS ISO_CALENDAR_WEEK FROM DUAL
CONNECT BY (DATE '2014-01-01' LEVEL) < DATE '2023-01-01' )
SELECT GROUP_ID,
ISO_CALENDAR_WEEK,
PROMOTION_DESCRIPTION,
MEDIA_SUPPORT
FROM CALENDAR
INNER JOIN PROMOTION
ON ISO_CALENDAR_WEEK
BETWEEN START_YEARWEEK AND END_YEAR_WEEK;
Результат:
GROUP_ID ISO_CALENDAR_WEEK PROMOTION_DESCRIPTION MEDIA_SUPPORT
40315 201727 Voordeelzakken En Dozen Online Campagne
40284 201726 Gehwol / Wartner 2e halve prijs Radio
40315 201726 Voordeelzakken En Dozen Online Campagne
3 rows selected.
Комментарии:
1. Привет, Alexgibbs, это отличный ответ, и он работает как шарм! Только я работаю с неделями ISO, поэтому они идут только на 52-ю неделю в 2016-2018 годах, но в 2015 году 53 недели. Если мне нужно объединить эти данные, как бы вы порекомендовали мне это сделать? Я мог бы легко удалить дополнительные недели в годах с 52 неделями, но есть ли какой-либо способ автоматизировать это при создании календаря? Спасибо!
2. Спасибо @J4YJ4Y. Конечно, календарь может быть изменен по мере необходимости. Я обновлю его примером ISO.
3. Ok @J4YJ4Y добавлен пример с неделями ISO
Ответ №2:
Этот рекурсивный запрос может это сделать:
with c(rn, group_id, week, weeks, promotion_description, media_support) as (
select 1, group_id, start_yearweek, weeks, promotion_description, media_support from t
union all
select rn 1, group_id, week 1, weeks, promotion_description, media_support
from c where rn < weeks)
select group_id, week, weeks, promotion_description, media_support from c
Комментарии:
1. Эй, обдумайте, спасибо за быстрый ответ! Хотя это будет работать для 2-недельных рекламных акций, что бы это сделало, если бы у меня была акция продолжительностью 33 недели?
2. Нет, рекурсивный запрос работает в течение любого количества недель, он выдаст 33 строки для этой записи. Вот dbfiddle , где я добавил строку с 33 неделями. Проблема только в том, что при изменении года мы должны назначить последнюю неделю (как я понял), что требует некоторых преобразований даты. В моей демонстрации вы можете увидеть пример.
Ответ №3:
Вы можете использовать такую комбинацию connect by level
стилей ниже, чтобы создать больше строк в зависимости от ваших данных и ограничить их определенным количеством, управляя с помощью distinct
ключевого слова.
with t( group_id, promotion_description, start_yearweek, end_yearweek, media_support ) as
(
select 40284, 'Gehwol / Wartner 2e halve prijs', 201726, 201726, 'Radio' from dual union all
select 40315, 'Voordeelzakken En Dozen', 201726, 201727, 'Online Campagne' from dual
), t1 as
(
select group_id,
sum(end_yearweek - start_yearweek 1 ) as weeks
from t
group by group_id
)
select distinct t1.group_id, start_yearweek level - 1 as week,
promotion_description, media_support
from t1
join t on t1.group_id = t.group_id
connect by level <= weeks
order by group_id, week;
GROUP_ID WEEK PROMOTION_DESCRIPTION MEDIA_SUPPORT
-------- ------ ------------------------------- ---------------
40284 201726 Gehwol / Wartner 2e halve prijs Radio
40315 201726 Voordeelzakken En Dozen Online Campagne
40315 201727 Voordeelzakken En Dozen Online Campagne
P.S. Нет необходимости хранить weeks
столбец, который может быть вычислен с помощью запроса.
Комментарии:
1. Привет, Барбарос, спасибо за этот отличный ответ! Кажется, это работает, пока у меня не появится повышение, которое длится 4 недели и начинается на 52 неделе года. Затем внезапно вместо 4 строк у меня получается 52 строки.. Есть ли какой-либо способ исправить это? Нравится работать с датой?
2. @J4YJ4Y добро пожаловать. Количество созданных строк зависит от разницы между
start_yearweek
иend_yearweek
для каждойgroup_id
. Это можно наблюдать, когда мы добавляем больше примеров операторов select в запрос, который создает таблицуt
.