Аналитическая функция Teradata Windows для выбора правильных записей из раздела

У меня есть всего два столбца для разделения, и на основе этих двух столбцов нужно выбрать соответствующие даты.

Входные данные:

strt_dt конец_дт ИДЕНТИФИКАТОР Амт 2023-09-29 01.10.2023 ID1 100 2023-10-02 2023-10-02 ID1 100 2023-10-03 2023-10-03 ID1 100 2023-10-04 2023-10-04 ID1 200 05.10.2023 05.10.2023 ID1 100

Ожидаемый результат:

strt_dt конец_дт ИДЕНТИФИКАТОР Амт 2023-09-29 2023-10-03 ID1 100 2023-10-04 2023-10-04 ID1 200 05.10.2023 05.10.2023 ID1 100

Фактический результат:

strt_dt конец_дт ИДЕНТИФИКАТОР Амт 2023-09-29 05.10.2023 ID1 100 2023-10-04 2023-10-04 ID1 200

Я использовал min(strt_dt) OVER (PARTITION by id, amt ORDER BY strt_dt), что является причиной дублирования результатов.

Нужно ли мне делать что-то по-другому?

Не могли бы вы добавить в вопрос sql-запрос, который вы пробовали?

Lisan Al Gaib 23.08.2024 05:27
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
2
1
50
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Этого можно добиться двумя способами: я приведу как простой, так и сложный варианты.

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;

Я использовал первый подход. Спасибо.

user2653353 23.08.2024 10:54

Вы хотите объединить смежные строки, у 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

Другие вопросы по теме