如何在 Bigquery 中使用字段历史 table 重新创建旧快照

How to recreate old snapshot using field history table in Bigquery

我目前正在研究一个有趣的问题。我正在尝试重新创建 table 的状态,因为它是在给定的先前日期。我有 2 tables

  1. Table A:由实时数据组成,每小时刷新一次。
  2. Table A_field_history:包含对 Table A.
  3. 中字段所做的更改

下图包含当前状态,其中 Table A 具有实时更新数据,Table A_field_history 仅捕获对 table A 上的字段所做的更改。

我正在尝试重新创建特定给定日期的 Table A。下图包含 2020 年 6 月 30 日的 table 个状态。 要求是能够根据任何给定日期重新创建 Table A 的状态。

我实际上确定了一种方法来回滚(实际上,不是实际 table)在给定特定日期之后进行的所有更新。以下是遵循的步骤:

创建虚拟 tables:

WITH
Table_A AS
(
SELECT 1 As ID, '2020-6-28' as created_date, 10 as qty, 100 as value
Union ALL
SELECT 2 As ID, '2020-5-29' as created_date, 20 as qty, 200 as value),

Table_A_field_history AS
(
SELECT 'xyz' id,'2020-07-29'    created_date,'12345'    created_by,'qty'    field,'10'  new_value,'200' old_value,'1'   A_id
UNION ALL
SELECT 'abc' id,'2020-07-24'    created_date,'12345'    created_by,'qty'    field,'20'  new_value,'10' old_value,'2'    A_id
UNION ALL
SELECT 'xyz' id,'2020-07-29'    created_date,'12345'    created_by,'value'  field,'100' new_value,'2000' old_value,'1'  A_id
UNION ALL
SELECT 'abc' id,'2020-07-24'    created_date,'12345'    created_by,'value'  field,'200' new_value,'5000' old_value,'2'  A_id
UNION ALL

SELECT 'xyz' id,'2020-06-29'    created_date,'12345'    created_by,'qty'    field,'200' new_value,'' old_value,'1'  A_id
UNION ALL
SELECT 'abc' id,'2020-05-30'    created_date,'12345'    created_by,'qty'    field,'10'  new_value,'' old_value,'2'  A_id
UNION ALL
SELECT 'xyz' id,'2020-06-29'    created_date,'12345'    created_by,'value'  field,'2000'    new_value,'' old_value,'1'  A_id
UNION ALL
SELECT 'abc' id,'2020-05-30'    created_date,'12345'    created_by,'value'  field,'5000'    new_value,'' old_value,'2'  A_id

),

第 1 步。创建日期 cte 以根据给定日期过滤数据:

`date_spine 
AS

(
SELECT * FROM UNNEST(GENERATE_DATE_ARRAY('2020-01-01', CURRENT_DATE(), INTERVAL 1 Day)) AS as_of_date 
),`

第 2 步。以上创建日期 cte 可用作我们查询的 Spine,交叉连接到地图 as_of_date,其中包含历史记录中所做的所有更改 table。

    date_changes
AS
(
SELECT DISTINCT
date.as_of_date,
hist.A_id 
FROM Table_A_field_history hist CROSS JOIN date_spine date
),

第 3 步。现在我们已经 as_of_date 映射到所有历史交易,现在我们可以获得更改日期的最大值。

most_recent_changes AS (
  SELECT
    dc.as_of_date,
    dc.A_id ,
    MAX(fh.created_date) AS created_date,
  FROM date_changes dc
  LEFT JOIN Table_A_field_history AS fh
    ON dc.A_id   = fh.A_id  
  WHERE CAST(fh.created_date AS DATE) <= dc.as_of_date
  GROUP BY  dc.as_of_date,
    dc.A_id 
),

第 4 步。现在将最大更改日期映射到实际 created_date 和历史 table

past_changes AS (
  SELECT
    mr.as_of_date,
    mr.A_id,
    mr.created_date,
    a.id AS entry_id,
    a.created_by AS created_by_id,
    CASE WHEN a.field='qty' THEN a.new_value ELSE '' END AS qty,
    CASE WHEN a.field='value' THEN a.new_value ELSE '' END AS value,
  FROM most_recent_changes AS mr
  LEFT JOIN Table_A_field_history AS a
    ON mr.A_id  = a.A_id 
    AND mr.created_date = a.created_date
  WHERE a.id IS NOT NULL
)

第 5 步。现在我们可以使用 as_of_date 获取 Table A 的历史状态。

Select *
From past_changes x
WHERE x.as_of_date = '2020-07-29'