Google bigquery 附加具有不同模式的文件-BigQuery
我正在尝试将多个CSV文件附加到BigQuery中的一个表中。问题是它们没有相同的模式。它们有键,但字段不同。以下是一个例子: file1.csvGoogle bigquery 附加具有不同模式的文件-BigQuery,google-bigquery,Google Bigquery,我正在尝试将多个CSV文件附加到BigQuery中的一个表中。问题是它们没有相同的模式。它们有键,但字段不同。以下是一个例子: file1.csv ID A B C 1 T T T 2 F T F 3 F F F 文件2.csv ID A B D 1 T T T 4 F
ID A B C
1 T T T
2 F T F
3 F F F
文件2.csv
ID A B D
1 T T T
4 F T F
5 F F F
合并这些文件的最佳方式是什么
ID A B C D
1 T T T T
2 F T F
3 F F F
4 F T F
5 F F F
当将JSON文件加载到BigQuery中时,它会很高兴地识别并将其加载到正确的列中,正如JSON在每个记录中清楚地指出它希望加载数据的列一样。同时,对于CSV,您不能拥有相同的功能:当您将CSV表加载到BigQuery中时,BigQuery只会按照表和CSV的相同顺序将列映射到表
因此,如果您有不同的CSV模式,您将需要将它们加载到不同的BigQuery表中,并在稍后使用insert等将它们映射。最有可能的情况是,您需要最后一个表,然后将其用作其他表的联接-在这种情况下,使用类似枢轴的模式并不是最有效的选择-因此我建议考虑以下选项,将原始矩阵展平为ID-列-值模式 在下面的示例中-我假设您拥有具有真/假值的功能集,因此我可以使用逻辑AND或or轻松协调“冲突”值-但如果您实际具有“T”、“F”等字符串,则同样的方法也会起作用(当然,在这种情况下,下面的代码需要稍微调整) 下面是BigQuery标准SQL,在应用此代码之前,只需将所有文件加载到单独的表中(file1>table1、file2>table2等) 您可以根据需要在下面添加任意多的行
UNION ALL
SELECT ID, col, val FROM `project.dataset.tableX` t, UNNEST(x(TO_JSON_STRING(t)))
您可以使用问题中的示例数据测试、播放上述内容,如下例所示
#standardSQL
CREATE TEMP FUNCTION x(t STRING) AS ((
ARRAY(SELECT AS STRUCT col, val = 'true' val FROM
UNNEST(REGEXP_EXTRACT_ALL(t, r',"(.+?)":(?:true|false)')) col WITH OFFSET
JOIN UNNEST(REGEXP_EXTRACT_ALL(t, r',".+?":(true|false)')) val WITH OFFSET
USING(OFFSET))
));
WITH `project.dataset.table1` AS (
SELECT 1 ID, TRUE A, TRUE B, TRUE C UNION ALL
SELECT 2, FALSE, TRUE, FALSE UNION ALL
SELECT 3, FALSE, FALSE, FALSE
), `project.dataset.table2` AS (
SELECT 1 ID, TRUE A, TRUE B, TRUE D UNION ALL
SELECT 4, FALSE, TRUE, FALSE UNION ALL
SELECT 5, FALSE, FALSE, FALSE
)
SELECT id, col, LOGICAL_OR(val) val
FROM (
SELECT ID, col, val FROM `project.dataset.table1` t, UNNEST(x(TO_JSON_STRING(t)))
UNION ALL
SELECT ID, col, val FROM `project.dataset.table2` t, UNNEST(x(TO_JSON_STRING(t)))
)
GROUP BY id, col
-- ORDER BY id, col
结果
Row id col val
1 1 A true
2 1 B true
3 1 C true
4 1 D true
5 2 A false
6 2 B true
7 2 C false
8 3 A false
9 3 B false
10 3 C false
11 4 A false
12 4 B true
13 4 D false
14 5 A false
15 5 B false
16 5 D false
根据我在大多数情况下的经验,使用上述扁平模式比您最初期望的模式(在您的问题中)更简单、更容易。BigQuery没有键的概念,因此如果您将具有相同ID列的两个文件“附加”在一起,它们将不会合并。但是,如果您只想加载两个具有不同模式的文件并在其中附加数据,那么您可以非常轻松地完成这项工作。您可以告诉bigquery使用模式更新选项进行加载,该选项表示允许模式更改。您还应该传递要添加的文件的显式架构。因此,在你的情况下: 如果您有源文件:
$ cat one.csv
ID,A,B,C
1,T,T,T
2,F,T,F
3,F,F,F
$ cat two.csv
ID,A,B,D
1,T,T,T
4,F,T,F
5,F,F,F
然后你就可以做了
$ bq load --source_format=CSV --schema=id,a,b,c --skip_leading_rows=1 temp.test one.csv
Current status: DONE
$ bq load --source_format=CSV --schema=id,a,b,d --schema_update_option=ALLOW_FIELD_ADDITION --skip_leading_rows=1 temp.test two.csv
Current status: DONE
$ bq head temp.test
+----+---+---+------+------+
| id | a | b | d | c |
+----+---+---+------+------+
| 1 | T | T | NULL | T |
| 2 | F | T | NULL | F |
| 3 | F | F | NULL | F |
| 1 | T | T | T | NULL |
| 4 | F | T | F | NULL |
| 5 | F | F | F | NULL |
+----+---+---+------+------+
然而,这并不是你所说的你想要的;您似乎希望合并ID为1的行,以便它具有来自两个文件的数据
最好的方法是加载到两个单独的表,然后进行连接。如果加载到temp.t1和temp.t2表,则只需连接两个表即可。如
$ bq load --source_format=CSV --schema=id,a,b,c --skip_leading_rows=1 temp.t1 one.csv
Current status: DONE
$ bq load --source_format=CSV --schema=id,a,b,d --skip_leading_rows=1 temp.t2 two.csv
Current status: DONE
$ bq query --nouse_legacy_sql "SELECT IFNULL(t2.id, t1.id) as id, IFNULL(t2.a, t1.a) as a, IFNULL(t2.b, t1.b) as b, t1.c as c, t2.d as d FROM temp.t1 as t1 FULL OUTER JOIN temp.t2 as t2 ON t1.id = t2.id ORDER BY id"
Current status: DONE
+----+---+---+------+------+
| id | a | b | c | d |
+----+---+---+------+------+
| 1 | T | T | T | T |
| 2 | F | T | F | NULL |
| 3 | F | F | F | NULL |
| 4 | F | T | NULL | F |
| 5 | F | F | NULL | F |
+----+---+---+------+------+
你到底想做什么?最终的目标是有效地合并这两个文件,其中D列被视为实际名为C?或者你想在加载后把D作为一个单独的列来处理吗?是的,我想把D作为一个新的列来处理。刚刚添加了结果表。您如何决定ID=1使用哪些值?从文件1还是文件2?还是其他逻辑?
$ bq load --source_format=CSV --schema=id,a,b,c --skip_leading_rows=1 temp.t1 one.csv
Current status: DONE
$ bq load --source_format=CSV --schema=id,a,b,d --skip_leading_rows=1 temp.t2 two.csv
Current status: DONE
$ bq query --nouse_legacy_sql "SELECT IFNULL(t2.id, t1.id) as id, IFNULL(t2.a, t1.a) as a, IFNULL(t2.b, t1.b) as b, t1.c as c, t2.d as d FROM temp.t1 as t1 FULL OUTER JOIN temp.t2 as t2 ON t1.id = t2.id ORDER BY id"
Current status: DONE
+----+---+---+------+------+
| id | a | b | c | d |
+----+---+---+------+------+
| 1 | T | T | T | T |
| 2 | F | T | F | NULL |
| 3 | F | F | F | NULL |
| 4 | F | T | NULL | F |
| 5 | F | F | NULL | F |
+----+---+---+------+------+