Teradata, данные транзакций, где столбцы имеют отдельные даты обновления - PullRequest
0 голосов
/ 20 мая 2018

Я работаю над запросом Teradata, где я хотел бы найти последнее значение для нескольких столбцов.Каждый столбец данных связан со столбцом даты (дата обновления).Заголовок моей таблицы должен помочь понять мою проблему: идентификатор Attr_1 Attr_1_Update_Dt Attr_2 Attr_2_Update_Dt Attr_3 Attr_3_Update_Dt

Мне нужно выбрать Attr_1, каждый Attr_2 и последний идентификатор для каждого (для каждого атрибута) (для каждого атрибута) для каждого (для каждого атрибута) (последний идентификатор для каждого) (для каждого идентификатора Attr_3)Я уже думал о запуске отдельных рангов (путем обновления DT) для каждого из атрибутов, а затем объединить их в одну таблицу.Но я не думаю, что это слишком сложно (более того, когда у меня есть 8 столбцов атрибутов).

Надеюсь, что этого достаточно, чтобы помочь мне.С нетерпением жду вашего ответа.

Спасибо!

Ответы [ 2 ]

0 голосов
/ 21 мая 2018

Я бы предпочел, чтобы вы хранили ваши данные в обычном порядке.Пока это не будет сделано, вы будете прокляты, если для выполнения таких задач вам понадобятся более сложные запросы.

Способ обработки данных, как есть, заключается в использовании функции GREATEST (), но по какой-то причине, известной толькоРазработчики Teradata эта функция не принимает даты, но они могут быть приведены к целым числам, которые она принимает.Также необходимо избегать значений NULL.Это может дать вам самую последнюю дату в строке, и оттуда вы можете использовать ROW_NUMBER (), чтобы получить строки с самой последней датой для идентификатора.

WITH cte AS (     SELECT 
                         ID
                       , Attr_1
                       , Attr_2
                       , Attr_3
                       , CAST(GREATEST( 
                                CAST(COALESCE(Attr_1_Update_Dt, date '1900-01-01') AS INT)
                              , CAST(COALESCE(Attr_2_Update_Dt, date '1900-01-01') AS INT)
                              , CAST(COALESCE(Attr_3_Update_Dt, date '1900-01-01') AS INT)
                              , CAST(COALESCE(Attr_4_Update_Dt, date '1900-01-01') AS INT)
                              , CAST(COALESCE(Attr_5_Update_Dt, date '1900-01-01') AS INT)
                              , CAST(COALESCE(Attr_6_Update_Dt, date '1900-01-01') AS INT)
                              , CAST(COALESCE(Attr_7_Update_Dt, date '1900-01-01') AS INT)
                              , CAST(COALESCE(Attr_8_Update_Dt, date '1900-01-01') AS INT)
                         )as date) as maxdate
                  FROM yourtable)
SELECT
       ID
     , Attr_1
     , Attr_2
     , Attr_3
     , maxdate
FROM (
      SELECT
             ID
           , Attr_1
           , Attr_2
           , Attr_3
           , maxdate
           , ROW_NUMBER() OVER(PARTITION BY ID
                               ORDER BY maxdate DESC) as rn
      FROM cte
      ) d
WHERE rn = 1

Я не могу точно оценить производительность этого подхода, вероятно, он лучше всего подходит для стола среднего размера.Если ваша таблица очень большая, тогда я действительно изучу варианты нормализации данных.

0 голосов
/ 20 мая 2018

Есть несколько способов получить ваш результат.

Вы можете применить FIRST_VALUE для каждого дополнительного атрибута:

select
   Attr_1, Attr_1_Update_Dt,
   first_value(Attr_2) over (order by Attr_2_Update_Dt DESC),
   max(Attr_2_Update_Dt ) over (),
   ...
   first_value(Attr_n) over (order by Attr_n_Update_Dt DESC),
   max(Attr_2_Update_Dt ) over ()
from myTable
qualify row_number() over (order by Attr_1_Update_Dt DESC) = 1 -- only 1 row

Для этого требуется дополнительный шаг STATS в Explan для каждого атрибута, использование ресурсов может быть высоким при большой таблице.

В этом случае нормализация вашей таблицы может повысить производительность, либо:

select 1 as attr#, Attr_1, Attr_1_Update_Dt from myTable
union all 
select 2 as attr#, Attr_2, Attr_2_Update_Dt from myTable
...
union all
select n as attr#, Attr_n, Attr_n_Update_Dt from myTable

, либо CROSS JOIN к таблице с номерами от 1 до n (вероятно, более эффективной):

select 
   num as attr#, 
   case when num = 1 then Attr_1 end,
   case when num = 1 then Attr_1_Update_Dt end,
   case when num = 2 then Attr_2 end,
   case when num = 2 then Attr_2_Update_Dt end,
   ...
   case when num = n then Attr_1 end,
   case when num = n then Attr_1_Update_Dt end
from myTable 
cross join
  (
    Select returning "num" from 1 to n
  ) dt

Или используя TD_UNPIVOT или UNPIVOT в более новых версиях ...

Тогда это просто

select *
from 
 (
   normalizing Select
 ) as dt
qualify
   row_number()
   over (partition by num
         order by Attr_1_Update_Dt DESC) = 1
...