#loops #db2
#циклы #db2
Вопрос:
В настоящее время у меня есть запрос, настроенный через объединения [блок кода 1] для сбора данных. Это работает правильно, но очень неэффективно повторять это так много раз
Есть ли способ преобразовать это в цикл while в DB2?
Я пытался написать цикл while в [Блок кода 2], но это не работает в DB2.
Я продолжаю получать синтаксическую ошибку в Code_block_2
В блоке кода 2 я хочу добавить 1 к переменным даты начала и окончания, чтобы следующий запрос выполнялся с новыми периодами времени (сохраненными в виде целых чисел), например, первый раз будет между 201601 и 201701, второй раз будет между 201602 и 201702. Я попытался настроить end_dt для печати с каждой строкой данных
Метод объединения работает, но мне приходится писать один и тот же фрагмент кода несколько раз. Цикл был бы более эффективным
[блок кода 1 — Объединение (работает)]
select
1 as a.period,
a.name,
a.date
from
data_table
where
month between 201601 and 201701
union
select
1 as period,
a.name,
a.date
from
data_table a
where
a.month between 201602 and 201702 -- this is changing in a consistent pattern
union
select
1 as period,
a.name,
a.date
from
data_table a
where
a.month between 201603 and 201703
[Блок кода 2 — с попыткой выполнения цикла]
Begin atomic
declare @end_dt integer default 201701;
declare @start_dt integer default 201601;
while @end_dt < 201712 do
--statement
select
@end_dt as period,
a.name,
a.date
from
data_table a
where
month between @start_dt and @end_dt;
-- add 1 to variables
set @end_dt = @end_dt 1;
set @start_dt = @start_dt 1;
end while;
end;
вот пример набора данных
(В базе данных)
имя — дата Джейн — 5/2/2016
Джим — 6/3/2016
Зак — 1/1/2016
Джилл — 5/1/2016
Джо — 1/1/2016
Джеймс — 4/1/2016
Зои — 2/2/2016
Вывод (ожидаемый и результат блока кода 1.)
Период — Имя — дата
201701 — Джейн — 5/2/2016
201701 — Джим — 6/3/2016
201701 — Зак — 1/1/2016
201701 — Джилл — 5/1/2016
201701 — Джо — 1/1/2016
201701 — Джеймс — 4/1/2016
201701 — Зои — 2/2/2016
201702 — Джейн — 5/2/2016
201702 — Джим — 6/3/2016
201702 — Джилл — 5/1/2016
201702 — Джеймс — 4/1/2016
201702 — Зои — 2/2/2016
— обратите внимание, как даты 1/1/2016 отклоняются от установленного в 201702 году периода
Я не уверен на 100% в версии DB2, но она соответствует DB2 для Linux Unix и Windows 10.5 и z / OS
Комментарии:
1. Вы понимаете, что ваши диапазоны перекрываются? Почему бы вам просто не использовать один диапазон, включающий их все?
2. Я уверен, что диапазоны должны перекрываться. Это помогает получить итоговые данные с начала года за этот период. Например, если месяц 201701, я хочу, чтобы действие включало последние 12 месяцев.
3. Но вы теряете все эти значения при ОБЪЕДИНЕНИИ или при отсутствии агрегации.
4. Если эти значения теряются при объединении. Должен ли я просто запустить запрос в большом диапазоне и вычислить итоги с начала года другим способом?
5. У меня проблема с вашим диапазоном дат — это включающая верхняя граница. Вы получаете 13 месяцев (1 год, 1 месяц) вместо 12 месяцев (1 год), что кажется неправильным. Вы должны использовать явную, эксклюзивную верхнюю границу —
<
— особенно если вы когда-либо планируете использовать день месяца.
Ответ №1:
Запустите следующий запрос как есть.
Это «виртуальная» таблица, range
которую вы ищете?
with t(n, m) as (
select 1, date(to_date(201601, 'YYYYMM')) from sysibm.sysdummy1
union all
select n 1, m 1 month
from t
where n<11
)
, range (start, end) as (
select year(m)*100 month(m) as start, year(m 1 year)*100 month(m 1 year) as end
from t
)
select start, end
from range r;
Если да, то вы можете объединить эту range
таблицу со своим data_table
условием a.month between r.start and r.end
, чтобы получить указанный вами результат.
Ответ №2:
Есть ли у вас в системе таблица date dim / calendar?
Если нет, я просто добавляю таблицу значений. Это можно изменить на все, что вам нужно. Ему просто нужно иметь список значений даты ГГГГ за требуемый период.
select
dates.period,
a.name,
a.date
from
table( values
(201701)
,(201702)
,(201703)
,(201704)
,(201705)
,(201706)
,(201707)
,(201708)
,(201709)
,(201710)
,(201711)
,(201712)
) date(period)
join
data_table
on a.month between (date.period - 100) and date.period