У меня есть всего два столбца для разделения, и на основе этих двух столбцов нужно выбрать соответствующие даты.
Входные данные:
Ожидаемый результат:
Фактический результат:
Я использовал min(strt_dt) OVER (PARTITION by id, amt ORDER BY strt_dt)
, что является причиной дублирования результатов.
Нужно ли мне делать что-то по-другому?
Этого можно добиться двумя способами: я приведу как простой, так и сложный варианты.
ROW_NUMBER()
подойдет для этого требования, однако вам придется использовать его дважды (сначала без суммы, а затем с суммой). Приведенный ниже подход представляет собой простую версию,
WITH consecutive_blocks AS (
SELECT
strt_dt,
end_dt,
ID,
Amt,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY strt_dt) AS rn1,
ROW_NUMBER() OVER (PARTITION BY ID, Amt ORDER BY strt_dt) AS rn2
FROM
table_a
)
SELECT
MIN(strt_dt) AS strt_dt,
MAX(end_dt) AS end_dt,
ID,
Amt
FROM
consecutive_blocks
GROUP BY
ID, Amt, (rn1 - rn2)
ORDER BY
strt_dt;
Существует эффективный способ достижения того же результата, но он будет более сложным.
WITH flagged_rows AS (
SELECT
strt_dt,
end_dt,
ID,
Amt,
CASE
WHEN LAG(Amt) OVER (PARTITION BY ID ORDER BY strt_dt) = Amt THEN 0
ELSE 1
END AS flag
FROM
table_a
),
grouped_rows AS (
SELECT
strt_dt,
end_dt,
ID,
Amt,
SUM(flag) OVER (PARTITION BY ID ORDER BY strt_dt ROWS UNBOUNDED PRECEDING) AS grp
FROM
flagged_rows
)
SELECT
MIN(strt_dt) AS strt_dt,
MAX(end_dt) AS end_dt,
ID,
Amt
FROM
grouped_rows
GROUP BY
ID, Amt, grp
ORDER BY
strt_dt;
Я использовал первый подход. Спасибо.
Вы хотите объединить смежные строки, у Teradata есть хороший синтаксис для этого. Поскольку он основан на стандартной логике SQL PERIOD (начало и конец являются инклюзивными/исключающими), но ваша реализация использует инклюзивное/инклюзивное начало/конец, вам необходимо настроить дату окончания:
SELECT NORMALIZE -- this does all the magic
PERIOD(strt_dt, NEXT(end_dt) AS d -- adjust end date to make it inclusive
,ID
,Amt
FROM mytable;
Это возвращает период, если вы хотите разделить его на начало/конец:
WITH cte AS
(
SELECT NORMALIZE
PERIOD(strt_dt, NEXT(end_dt) AS d
,ID
,Amt
FROM mytable
)
SELECT
BEGIN(pd) AS strt_dt
,LAST(pd) AS end_dt -- returns the last included date
,ID
,amt
FROM cte
Не могли бы вы добавить в вопрос sql-запрос, который вы пробовали?