根据临时表

时间:2016-11-14 07:03:49

标签: database oracle postgresql database-design amazon-redshift

我有一个巨大的快照表(例如user_snapshot_all)分成Redshift(即Postgres)上的不同小表,以获得性能提升。

所以,较小的表就像(后缀有year_month)

user_snapshot_1995_1
user_snapshot_1995_2
user_snapshot_1995_3
user_snapshot_1995_4
....
user_snapshot_2016_11

他们拥有后缀

的年份和月份的快照记录

我使用临时表user_snapshot_staging逐步加载/更新这些表的数据,在99%的情况下,它只是最新的year_month表。

但是会有一些边缘情况,如午夜12:00,当临时表将有数据跨越两个表(例如2016-11-1上的user_snaspshot_2016_10和user_snapshot_2016_11) 或者另一个边缘情况,也许我们需要更新几个2年的快照,因此登台表将有一些2年的记录以及今天的很多快照。

问题是我应该如何设计我的查询或代码,以便它可以更新或插入正确的month_year快照表中的数据?

所有快照表和登台表至少包含以下两列:

id
snapshot_date

进一步澄清: 如果它是单个user_snapshot_all,我可以通过基于snapshot_date和id将登台表与主表连接来轻松更新记录。但是这些较小的表按month_year分段,不能保证在一个快照表中可以找到来自登台表的所有记录。

以下是用例 注意:以下查询是ETL流程的一部分,它们不是一次性手动的,这就是我需要自动化解决方案的原因。

场景1) 假设user_snapshot_staging表有

id  snapshot_date user_detail
100  2016-11-3     jskesljd234
101  2016-11-4     jskesljdfg23
102  2016-11-5     jskesljdbd23
103  2016-11-6     jskesljdw23ds

由于所有快照都属于2016年11月,所有这些数据都将被插入/更新到user_snapshot_2016_11中,并带有以下两个查询:

插入新内容:

Insert into user_info_snapshot_2011_11 (id, snapshot_date, user_detail )
from user_info_snapshot_staging source LEFT OUTER JOIN user_info_snapshot_2011_11 target on source.id = target.id where target.id is null
;

更新现有资料:

update user_info_snapshot_2011_11 set snapshot_date=source.snapshot_date, user_detail=source.user_detail 
from user_info_snapshot_staging source INNER JOIN user_info_snapshot_2011_11 target on source.id = target.id where

场景2) 现在假设user_snapshot_staging表有

id  snapshot_date user_detail
1300  2015-01-3     jskesljd234
1301  2015-10-4     jskesljdfg23
1302  2016-11-1     jskesljdbd23
1303  2016-11-2     jskesljdw23ds

现在登台表有快照,需要更新并插入到不同的快照表,我们不能只插入/更新到user_snapshot_2016_11,但我们需要插入/更新到user_snapshot_2015_01和user_snapshot_2015_10

我应该如何设计生成动态查询的查询或代码来处理这些情况,以便只根据登台表中的数据将适当的表与user_snapshot_staging表连接?

如果您需要进一步澄清,请与我们联系。对不起,解释起来有点棘手。

1 个答案:

答案 0 :(得分:0)

您可以使用以下方法生成查询。我将基于python语法给出伪代码示例。

  1. 获取临时数据库中的年/月组合
  2. 
    SELECT DISTINCT to_char(date, 'YYYY-MM') FROM user_info_snapshot_staging;
    1. 以下是您的查询模板:
    2. -- insert_template.sql
      INSERT INTO user_info_snapshot_{{ year }}_{{ month }} (id, snapshot_date, user_detail )
      FROM user_info_snapshot_staging source LEFT OUTER JOIN user_info_snapshot_{{ year }}_{{ month }} target on source.id = target.id where target.id is null
      WHERE DATE_TRUNC('month', source.date) = {{ month }} AND DATE_TRUNC('year', source.date) = {{ year }};
      
      -- update_template.sql
      UPDATE user_info_snapshot_{{ year }}_{{ month }} SET snapshot_date=source.snapshot_date, user_detail=source.user_detail
      FROM user_info_snapshot_staging source INNER JOIN user_info_snapshot_{{ year }}_{{ month }} target on source.id = target.id where
      DATE_TRUNC('month', source.date) = {{ month }} AND DATE_TRUNC('year', source.date) = {{ year }};
      

      现在循环完成年/月对并执行这些查询:

      for year_month, in cursor.execute("SELECT to_char('YYYY-MM', date_columns) FROM user_info_snapshot_staging"):
          year, month = year_month.split('-')
          # this is where you generate sql
          sql = template('insert_template', context={
              'year': year,
              'month': month,
          })
          # here you execute it
          cursor.execute(sql)
      

      如果您需要更新大量记录,我建议不要使用updatethis question中的更多信息。