【问题标题】:How update a table in Big Query and store the original value replaced and her difference with the new value如何更新 Big Query 中的表并存储替换的原始值以及她与新值的差异
【发布时间】:2021-01-23 17:58:46
【问题描述】:

在以前的帖子中,请参见此处: How update a table in Big Query where the name of fields to update are values in another table

我有两个表和以下问题:

表 1:

+-------+------------+---------+
| ID    | field_name | value   |
+-------+------------+---------+
| 1     | usd        |  10.08  |
| 1     | gross_amt  |  52.0   |
| 1     | jpy        |  30.05  |
| 2     | usd        |  50.0   |
| 2     | eur        |  50.0   |
| 3     | real_amt   |  210.43 |
| 3     | total      |  320    |
| 4     | jpy        |  23.45  |
| 4     | name       |  john   |
| 4     | city       |  utah   |
+-------+------------+---------+

表 2:

+-----+-------+-----------+----------+---------+------+-------+-------+-------+-----------+----------+-------+-----+----------+
| ID  |  name | last_name |   date1  | counrty | city |  usd  |  eur  |  jpy  | gross_amt | real_amt | total | ... | field200 |
+-----+-------+-----------+----------+---------+------+-------+-------+-------+-----------+----------+-------+-----+----------+
| 1   |  jane | doe       | 19900108 |   usa   | LA   | 9.08  | 0.00  | 29.05 | 50.0      |  52.0    | 900.0 | ... | value200 |
| 2   |  lane | smith     | 19900108 |   usa   | LA   | 40.8  | 40.0  | 0.00  | 100.0     |  70.0    | 290.0 | ... | value200 |
| 3   |  mike | hoffa     | 19900108 |   usa   | SF   | 5.05  | 0.00  | 0.00  | 10.0      |  25.0    | 100.0 | ... | value200 |
| 4   |  paul | doe       | 19900108 |   usa   | NY   | 1.00  | 0.00  | 29.05 | 45.0      |  55.0    | 110.0 | ... | value200 |
+-----+-------+-----------+----------+---------+------+-------+-------+-------+-----------+----------+-------+-----+----------+

需要更新表2中字段的值,即表1中field_name列的值,用表1列value的值,两个表的ID相同,除此之外,表1中value列的数据类型是字符串,但表2中要更新的列的数据类型不同,尤其是数字(numeric, int64, float64)

上面的表格是一个例子,实际问题的表 2 有 200 个字段,在表 1 中,对于一个 ID,每天可以修改数千条记录,最多可以修改 40 个值

但现在我有一个新问题

在新表1(表3)中:

表 3:

+-------+------------+---------+-----------------------+------------------+
| ID    | field_name | value   | value_replaced_table2 |      diff        |
+-------+------------+---------+-----------------------+------------------+
| 1     | usd        |  10.08  |   9.08                | abs(10.08-9.08)  |
| 1     | gross_amt  |  52.0   |  50.0                 | abs(52.0-50.0)   |
| 1     | jpy        |  30.05  |  29.05                | abs(30.05-29.05) |
| 2     | usd        |  50.0   |  40.08                | abs(50.0-40.0)   |
| 2     | eur        |  50.0   |  40.0                 |       ......     |
| 3     | real_amt   |  210.43 |  25.0                 |       ......     |
| 3     | total      |  320    | 100.0                 |       ......     |
| 4     | jpy        |  23.45  |  29.05                | abs(23.45-29.05) |
| 4     | name       |  john   |  paul                 |       john       |
| 4     | city       |  utah   |  NY                   |       utah       |
+-------+------------+---------+-----------------------+------------------+

我需要在value_replaced_table2列的新表1(表3)中插入表2中替换的值,从而将替换的值存储在上面的表2中,并计算两个值之间的差异,(新值更新和替换表2中的旧值,注意新表1(表3)的数据类型是string,表2的数据类型是(numeric, int64, float64)

从现在开始,感谢您的回答!

【问题讨论】:

    标签: sql google-bigquery sql-update sql-insert execute-immediate


    【解决方案1】:

    使用之前创建的pivot1 表,您可以在使用table2 执行最终的MERGE 之前使用它来获取将更改的old_values

    然后,您需要对结果进行反透视以获得table3。使用示例数据的示例 :

    -- Same pivot1 table as before
    EXECUTE IMMEDIATE '''
    CREATE TEMP TABLE pivot1 AS
    SELECT id, ''' || (
      SELECT STRING_AGG(DISTINCT "MAX(IF(field_name = '" || field_name || "', CAST(value AS " || data_type || "), NULL)) AS " || field_name)
      FROM `project.dataset.table1`
      JOIN (
        SELECT column_name, data_type
        FROM `project.dataset.INFORMATION_SCHEMA.COLUMNS`
        WHERE table_name = 'replica2' 
      ) ON field_name = column_name
    ) || '''  
    FROM `project.dataset.table1`
    GROUP BY id
    ''';
    
    -- Table3
    EXECUTE IMMEDIATE '''
    CREATE OR REPLACE TABLE project.dataset.table3 AS
    SELECT a.id, values.column_name as field_name, values.new_value as value, values.old_value as value_replaced_table2,
     CASE
        WHEN values.data_type = "STRING" THEN values.new_value
        WHEN values.data_type = "INT64" THEN CAST(ABS(CAST(values.new_value AS INT64) - CAST(values.old_value AS INT64)) AS STRING)
        ELSE CAST(ABS(CAST(values.new_value AS FLOAT64) - CAST(values.old_value AS FLOAT64)) AS STRING)
     END as diff
    FROM (
    SELECT t1.id, [''' || (
      SELECT STRING_AGG(DISTINCT "STRUCT('" || column_name || "' as column_name, CAST(t1." || column_name || " AS STRING) as new_value, CAST(t2." || column_name || " AS STRING) as old_value, '" || data_type || "' as data_type)") 
      FROM `project.dataset.table1`
      JOIN (
        SELECT column_name, data_type
        FROM `project.dataset.INFORMATION_SCHEMA.COLUMNS`
        WHERE table_name = 'replica2' 
      ) ON field_name = column_name
    ) || '''] AS values
    FROM `project.dataset.table2` AS t2
    JOIN pivot1 AS t1
    ON t2.id = t1.id ) a
    CROSS JOIN UNNEST(a.values) as values
    WHERE values.new_value IS NOT NULL
    ''';
    
    SELECT * FROM `project.dataset.table3` ORDER BY id;
    

    请注意,FLOAT64 的差值在转换为 STRING 时会得到一个近似值,因此如果您想将差值四舍五入,可以使用转换为 NUMERIC 而不是 FLOAT64,例如:

    ...
    ELSE CAST(ABS(CAST(values.new_value AS NUMERIC) - CAST(values.old_value AS NUMERIC)) AS STRING)
    ...
    -- Instead of 9.20000000000000028, it will appear as 9.2
    

    【讨论】:

    • 它就像一个魅力!,我期待一个更新声明,但你的回答已经足够了,我用你的回答做更新声明,谢谢!
    • 是的,我不确定您想如何处理结果,所以我将表 3 包括在内。很高兴它有效!
    猜你喜欢
    • 2021-03-19
    • 1970-01-01
    • 2023-03-03
    • 2021-01-18
    • 1970-01-01
    • 2022-06-10
    • 1970-01-01
    • 2021-05-16
    • 1970-01-01
    相关资源
    最近更新 更多