我有一个巨大的快照表(例如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表连接?
如果您需要进一步澄清,请与我们联系。对不起,解释起来有点棘手。
答案 0 :(得分:0)
您可以使用以下方法生成查询。我将基于python语法给出伪代码示例。
SELECT DISTINCT to_char(date, 'YYYY-MM') FROM user_info_snapshot_staging;
-- 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)
如果您需要更新大量记录,我建议不要使用update
。 this question中的更多信息。