我正在尝试将数组传递给Google bigquery中的参数化查询(https://cloud.google.com/bigquery/docs/parameterized-queries#bigquery_query_params_arrays-python)。我的示例类似于BigQuery Using arrays in parameterized queries,但是那里的解决方案无法解决我的问题,并且遵循原始文档中的代码也不起作用。
这里有两段代码,一个参数生成器和sql本身。我尝试了多种组合,但都没有成功。
构建参数列表的代码在这里。值得注意的是,数组附加行末尾的注释部分是我尝试过的一种变体(基于另一个论坛),但也没有成功(稍后会对此进行更多介绍)。
# set bigquery query parameters
insert_etl_log_params = []
used_array_parameter = False
for key, value in params_dict.items():
if isinstance(value, list):
used_array_parameter=True
value_type=None
if isinstance(value[0],int):
value_type= 'INT64'
elif isinstance(value[0],float):
value_type= 'FLOAT64'
else:
value_type= 'STRING'
insert_etl_log_params.append(bigquery.ArrayQueryParameter(key,value_type,value)) #[str(value)[1:-1]]))
elif isinstance(value,int):
insert_etl_log_params.append(bigquery.ScalarQueryParameter(key, 'INT64', value))
elif isinstance(value,float):
insert_etl_log_params.append(bigquery.ScalarQueryParameter(key, 'FLOAT64', value))
else:
insert_etl_log_params.append(bigquery.ScalarQueryParameter(key, 'STRING', value))
稍后,我使用以下代码将以上内容插入查询本身:
job_config.query_parameters = insert_etl_log_params
这对于非数组查询很好。
这是我正在使用的(略有简化)查询,在使用非数组参数时也可以正常使用
SELECT
AVG(EXTRACT(DAY FROM date_id)) as DAY,
ANY_VALUE(date_id) as date_id,
AVG(outlet_id) as outlet_id,
SUM(sales_qty)as sales_qty
FROM
tablename AS table
WHERE
tablename.date_id BETWEEN @begin_date AND @end_date AND -- Limit search by date
tablename.outlet_id IN UNNEST(@outlet_id) --Limit search to list of stores
GROUP BY EXTRACT(DAY FROM tablename.date_id),tablename.outlet_id
ORDER BY DAY, outlet_id
我尝试过的变化:
最初,我在sql中没有UNNEST命令并直接在查询构建器中使用value变量(例如完全如上面的代码块所示)尝试过它。这给了我这个错误:
400 POST project/jobs: Syntax error: Expected "(" or keyword UNNEST but got "@"
在查询中切换到UNNEST方法给我这个错误:
google.api_core.exceptions.BadRequest: 400 Second argument of IN UNNEST must be an array but was STRING
如果我将其打印出来,那时候我要传递给查询的列表是这样的:
[ScalarQueryParameter('begin_date', 'STRING', '2019-01-01'), ScalarQueryParameter('end_date', 'STRING', '2019-04-01'), ArrayQueryParameter('outlet_id', 'INT64', [415, 1013])]
在我看来,python和sql之间存在数据类型问题,但不确定如何解决。如果我在python中检查数组的类型,则两项都是int类型。
更改字典构建器的语法以使用[str(value)[1:-1]]))
,使整行如下:
insert_etl_log_params.append(bigquery.ArrayQueryParameter(key,value_type,[str(value)[1:-1]]))
这给了我这个错误:
ERROR: 400 POST project/jobs: Unparseable query parameter
outlet_id in type
TYPE_INT64 , Bad int64 value: 415, 1013 value: '415, 1013'
在这里,似乎转换为字符串只是给我一个不同的类型错误,并没有真正的帮助。
如果我删除了追加行上的括号,但保留了字符串转换(例如insert_etl_log_params.append(bigquery.ArrayQueryParameter(key,value_type,str(value)[1:-1]))
,则会出现此错误:
Unparseable query parameter
outlet_id in type
TYPE_INT64 , Bad int64 value: , value: ','
类似地,如果我回到原始值方法,但是这次像文档一样将其括起来(例如insert_etl_log_params.append(bigquery.ArrayQueryParameter(key,value_type,[value]))
),那么我又回到了这个错误:
google.api_core.exceptions.BadRequest: 400 Second argument of IN UNNEST must be an array but was STRING
所以最后我想我在python数组中的项目和sql读取它们的类型之间有类型错误,但是我不知道是什么原因或如何解决。有人看到我在做什么错吗?