【问题标题】:Tricky logic -SQL,Teradata棘手的逻辑——SQL、Teradata
【发布时间】:2015-10-14 15:19:45
【问题描述】:

这是一个我试图解决的棘手场景。 Table A1:有 4 列。并且此表每 2 天更新一次。

id    name  fav_color  date
2051  joe   white      07/21
2052  John  green      07/21

2 天后记录更新,table A1 看起来像这样。

id    name  fav_color  date
2051  joe   blue       07/23
2052  Rick  green      07/23

Table A2:这是一个历史记录表,记录了对table A1所做的所有更改。

id    updated_column   update_dt  old_value  new_value
2051  fav_color        07/23      white      blue
2052  Name             07/23      John       Rick 

现在企业希望在月底查看表 A1 的每月快照。 基本上我想要这样的每月快照。

id    name  fav_color  date
2051  joe   white      07/21
2051  joe   blue       07/23
2052  John  green      07/21
2052  Rick  green      07/23

请告诉我如何做到这一点。

【问题讨论】:

  • 这些是示例列,还是真实的?
  • 您希望表 A1 和 A2 中有多少条记录?
  • 您是否也在历史列中存储旧的date 值?因为如果您不知道,则无法知道 old_value 在该特定日期有效,而且我看不到获得所需输出的方法
  • @a_horse_with_no_name:只有记录的第一个值才会出现这个问题。那些日期是未知的。我们可能不得不忽略第一个值...

标签: sql database teradata


【解决方案1】:
SELECT id,name,fav_color,date
FROM tableA1

UNION ALL

SELECT tableA2.id,
       CASE WHEN tableA2.updatedColumn ='name' 
            THEN tableA2.oldValue
            ELSE tableA1.name END,
       CASE WHEN tableA2.updatedColumn ='fav_color' 
            THEN tableA2.oldValue
            ELSE tableA1.fav_color END,
       tableA2.update_dt
FROM tableA2
INNER JOIN tableA1 ON tableA2.id=tableA1.id
ORDER BY id

【讨论】:

  • 这真的行不通。两个 case 语句中的 else 都返回当前值,但它应该显示当时未更改的值。
【解决方案2】:

一种非常原始、缓慢且可能不完整的方式,应该或多或少地返回你需要的东西:

SELECT
  dates.id,
  dates.date,
  (SELECT TOP (1) name.new_value 
   FROM A2 name 
   WHERE name.id = dates.id and name.date <= dates.date and name.updated_column = 'name') as name,
  (SELECT TOP (1) favcol.new_value 
   FROM A2 favcol 
   WHERE favcol.id = dates.id and favcol.date <= dates.date and favcol.updated_column = 'fav_color') as fav_color
FROM A2 dates

按dates.id、dates.date排序

第一个值被忽略。这可能是一个起点。

【讨论】:

    【解决方案3】:

    有很多依赖关系,但这样的事情可能会做到。

    select 
     name.id
    , name.name 
    , color.fav_color 
    , color.update_dt
    from 
    (select 
     id
    ,update_dt
    ,new_value
    from a2
    where update_column = 'fav_color') color
    join 
    (select
     id
    ,update_dt
    ,new_value
    from a2
    where update_column = 'name') name
    on color.id = name.id and color.update_dt = name.update_dt
    order by color.update_dt, name.id
    

    【讨论】:

      【解决方案4】:

      您的 Teradata 版本是什么?

      在 TD14.10 中有 LAST_VALUE,可用于将 NULL 替换为之前的值:

      SELECT
         id,
         LAST_VALUE(name IGNORE NULLS) 
         OVER (PARTITION BY id 
               ORDER BY datecol DESC) AS name,
         LAST_VALUE(fav_color IGNORE NULLS) 
         OVER (PARTITION BY id 
               ORDER BY datecol DESC) AS fav_color,
         MAX(datecol) -- date of change, NULL for the first version
         OVER (PARTITION BY id 
               ORDER BY datecol DESC
               ROWS BETWEEN  1 FOLLOWING AND 1 FOLLOWING) AS detail
      FROM
       (
         SELECT id, NAME, fav_color, DATE '9999-12-31' AS datecol -- current version
         FROM a1
      
         UNION ALL
      
         SELECT -- previous versions
            id,
            MAX(CASE WHEN updated_column = 'name' THEN old_value END) AS name,
            MAX(CASE WHEN updated_column = 'fav_color' THEN old_value END) AS fav_color,
            update_dt
         FROM a2
         GROUP BY id, update_dt
       ) AS dt
      

      【讨论】:

        【解决方案5】:

        试试这个。
        select * from ( select id,name,fav_color,date1 from Table1 union all select t2.id, Case t2.updated_column when 'Name' then t2.new_value else t1.name End as name, Case t2.updated_column when 'fav_color' then t2.new_value else t1.fav_color End as fav_color, t2.update_dt as date1 from Table2 t2 Inner Join Table1 t1 on t1.id = t2.id )A order by 1 Asc

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2023-03-18
          • 2016-06-23
          • 1970-01-01
          • 1970-01-01
          • 2018-03-14
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多