在更新视图时,似乎不会采用间接模式更改。
view1
(例如field1
)创建SELECT 1 AS field1
view2
,从view1
中选择所有字段view1
使其也包含field2
(例如SELECT 1 AS field1, 2 AS field2
)view2
(由于documented limitation)view1
和view2
的架构,包括field1
和field2
view1
的架构已正确更新(包括field1
和field2
)view2
的架构仅包括field1
view2
中进行选择实际上会返回field1
和field2
我可以删除view2
并重新创建它,但这不是原子的,并且有时会出现视图不可用的情况。
我还尝试更新view2
的schema属性,但是Cannot add fields (field: field2)
拒绝了该属性:
google.api_core.exceptions.BadRequest:400 PATCH https://www.googleapis.com/bigquery/v2/projects/<project-id>/datasets/dataset1/tables/view2:提供的架构与表
:dataset1.view2不匹配。无法添加字段(字段:field2)
有什么方法可以自动更新视图,同时还可以更新间接更改的模式(视图从中选择的表/视图)。
注意:当然,我的view2将添加其他字段,并且我目前可以通过创建新的临时视图来确定其架构。
注意:该模式很重要,因为诸如Data Studio的BigQuery连接器之类的工具正在检查该模式。
# Python 3.6+
import google.api_core.exceptions
from google.cloud import bigquery
def delete_table_if_exists(client: bigquery.Client, table: bigquery.Table):
try:
client.delete_table(table)
except google.api_core.exceptions.NotFound:
pass
def full_table_id(table: bigquery.Table) -> str:
# Note: the documentation says it should be separated by a dot but uses a colon
return table.full_table_id.replace(':', '.')
def view_test():
client = bigquery.Client()
dataset_ref = client.dataset('dataset1')
try:
client.create_dataset(dataset_ref)
except google.api_core.exceptions.Conflict:
pass
view1 = bigquery.Table(dataset_ref.table('view1'))
view2 = bigquery.Table(dataset_ref.table('view2'))
delete_table_if_exists(client, view1)
delete_table_if_exists(client, view2)
view1.view_query = 'SELECT 1 AS field1'
view1 = client.create_table(view1)
view2.view_query = f'SELECT * FROM `{full_table_id(view1)}`'
client.create_table(view2)
view1.view_query = 'SELECT 1 AS field1, 2 AS field2'
client.update_table(view1, ['view_query'])
client.update_table(view2, ['view_query'])
print('view2 schema:', client.get_table(view2).schema)
# trying to update the schema fails with 'Cannot add fields (field: field2)'
view2.schema = client.get_table(view1).schema
client.update_table(view2, ['schema'])
if __name__ == '__main__':
view_test()
#!/bin/bash
set -e
project_id=$(gcloud config list --format 'value(core.project)' 2>/dev/null)
bq mk -f dataset1
bq rm -f dataset1.view1
bq rm -f dataset1.view2
bq mk --use_legacy_sql=false --view 'SELECT 1 AS field1' dataset1.view1
bq mk --use_legacy_sql=false --view 'SELECT * FROM `'$project_id'.dataset1.view1`' dataset1.view2
bq update --use_legacy_sql=false --view 'SELECT 1 AS field1, 2 AS field2' dataset1.view1
bq update --use_legacy_sql=false --view 'SELECT * FROM `'$project_id'.dataset1.view1`' dataset1.view2
bq show dataset1.view2
def get_create_or_replace_view_query(view: bigquery.Table) -> str:
return f'CREATE OR REPLACE VIEW {view.dataset_id}.{view.table_id} AS {view.view_query}'
def view_test():
# ...
query_job = client.query(get_create_or_replace_view_query(view2))
query_job.result()
print('view2 schema:', client.get_table(view2).schema)
bq query --use_legacy_sql=false 'CREATE OR REPLACE VIEW dataset1.view2 AS SELECT * FROM `'$project_id'.dataset1.view1`'
答案 0 :(得分:2)
您应该使用CREATE OR REPLACE VIEW
语句;请参阅related documentation。 BigQuery为所有执行表修改的查询提供ACID语义,CREATE OR REPLACE VIEW
也不例外,因此这原子地替换了视图的定义和架构。