Its kind of challenging to get such a script. Its possible although you might need to do a lot of coding and try-error. If a table is really extensive you might want to use python ( as suggested by martin weitzmann) to retrieve column information and create your script to get your data.
You can also use only BigQuery but you might find it difficult to implement on large tables but here is my approach, you can try this approach if it fits your scenario:
- Create our test table with some records
create or replace table`projectid.dataset.table`
(
id INT64,
ingestTimeStamp date,
payloadKV STRUCT<id INT64,json STRING>,
metaKV STRUCT<id INT64,description STRING>
)
insert into `projectid.dataset.table`(id,ingestTimeStamp,payloadKV,metaKV)values(1,"2022-03-03",(100,'{"kardexid":11,"desc":"d1"}'),(100,"a desc1"));
insert into `projectid.dataset.table`(id,ingestTimeStamp,payloadKV,metaKV)values(2,"2022-03-04",(101,'{"kardexid":22,"desc":"d2"}'),(110,"a desc2"));
insert into `projectid.dataset.table`(id,ingestTimeStamp,payloadKV,metaKV)values(3,"2022-03-05",(102,'{"kardexid":34,"desc":"d3"}'),(120,"a desc3"));
insert into `projectid.dataset.table`(id,ingestTimeStamp,payloadKV,metaKV)values(4,"2022-03-06",(103,'{"kardexid":53,"desc":"d4"}'),(130,"a desc4"));
- Lets declare our working variables
declare working_table string;
declare loop_col String;
declare query String;
declare single_col_names String;
declare nested_col_array ARRAY<STRING>;
declare nested_col_string String DEFAULT "";
- Set our working variables
# Set columns to work
set working_table = "table";
set single_col_names = (SELECT STRING_AGG(column_name) FROM `projectid.dataset.INFORMATION_SCHEMA.COLUMNS`
where table_name = working_table and data_type not like 'STRUCT%');
set nested_col_array = (SELECT ARRAY_AGG(column_name) FROM `projectid.dataset.INFORMATION_SCHEMA.COLUMNS`
where table_name = working_table and data_type like 'STRUCT%');
- Get our nested columns
# Retrieve nested columns
FOR record IN
(SELECT * FROM unnest(nested_col_array) as col_names)
DO
SET loop_col = (SELECT CONCAT(column_name,
".",
REPLACE(ARRAY_TO_STRING(REGEXP_EXTRACT_ALL(data_type,r'[STRUCT<,INT64 STRING ]+(.+?) '),",")
,",",
CONCAT(",",column_name,".")))
FROM `projectid.dataset.INFORMATION_SCHEMA.COLUMNS`
where table_name = working_table and data_type like 'STRUCT%' and column_name=record.col_names);
SET nested_col_string = (SELECT CONCAT(nested_col_string,",",loop_col));
END FOR;
- we then finalize by creating our custom query and run it.
# build & run query
set query = (SELECT FORMAT("select %s%s from `projectid.dataset.table` order by 1",single_col_names,nested_col_string));
EXECUTE IMMEDIATE(query);
output:
| id |
ingestTimeStamp |
id_1 |
json |
id_2 |
description |
| 1 |
2022-03-03 |
100 |
{"kardexid":11,"desc":"d1"} |
100 |
a desc1 |
| 2 |
2022-03-04 |
101 |
{"kardexid":22,"desc":"d2"} |
110 |
a desc2 |
| 3 |
2022-03-05 |
102 |
{"kardexid":34,"desc":"d3"} |
120 |
a desc3 |
| 4 |
2022-03-06 |
103 |
{"kardexid":53,"desc":"d4"} |
130 |
a desc4 |
As you can see, a process such as this one on BigQuery is quite challenging as you will have to parse your struct types to get the names of your inner columns, do scripting and definitely not optimal. For the sake of the question, this can be done but it's not something I would recommend.
When dealing with BigQuery you usually want to go for less resource invested queries and just pick up what is truly needed. You can use client libraries to perform less operations on BigQuery side and use the code to perform transformations with the data you get from your raw queries.
To create this code I consult the following documentation, check it out: