【问题标题】:Google BQ: Running Parameterized Queries where Parameter Variable is the BQ Table DestinationGoogle BQ:运行参数化查询,其中参数变量是 BQ 表目标
【发布时间】:2021-01-15 17:32:20
【问题描述】:

我正在尝试从 Linux 命令行为 BQ 表目标运行 SQL。此 SQL 脚本将用于多个日期、客户端和 BQ 表目标,因此这需要在我的 BQ API 命令行调用中使用参数(标志 --parameter)。现在,我通过此链接了解了参数化查询:https://cloud.google.com/bigquery/docs/parameterized-queries,但它在帮助我声明表名方面受到限制。

我的 SQL 脚本名为 Advertiser_Date_Check.sql,如下所示:

#standardSQL
SELECT *
FROM (SELECT *
      FROM @variable_table
      WHERE CAST(_PARTITIONTIME AS DATE) = @variable_date) as final
WHERE final.Advertiser IN UNNEST(@variable_clients)

其中参数变量代表如下:

  • variable_table:我要调用的 BQ 表目标
  • variable_date:我想从 BQ 表中提取的日期
  • variable_clients:我想从数据中提取的特定客户端的数组列表(从我引用的日期开始)

现在,我的 BQ 数据命令行 (LINUX) 如下

TABLE_NAME=table_name_example
BQ_TABLE=$(echo '`project_id.dataset_id.'$TABLE_NAME'`')
TODAY=$(date +%F)

/bin/bq query --use_legacy_sql=false    \
       --parameter='variable_table::'$BQ_TABLE''  \
       --parameter=variable_date::"$TODAY"    \
       --parameter='variable_clients:ARRAY<STRING>:["Client_1","Client_2","Client_3"]'  \
       "`cat /path/to/script/Advertiser_Date_Check.sql`" 

@variable_date 和 @variable_clients 的参数在过去只有它们时工作得很好。但是,由于我希望在循环中对各种表运行这个精确的 SQL 命令,所以我创建了一个名为 variable_table 的参数。参数化查询必须采用标准 SQL 格式,因此表名约定必须采用以下格式:

`project_id.dataset_id.table_name`

每当我尝试在命令行上运行它时,我通常会收到以下错误:

Error in query string: Error processing job ... : Syntax error: Unexpected "@" at [4:12]

这是引用参数@variable_table,因此很难处理这是引用表名。 在过去的尝试中,甚至出现过错误:

project_id.dataset_id.table_name: command not found

但这主要是由于对表目标名称的引用不佳。第一个错误是最常见的情况。

总的来说,我对此事的疑问是:

  1. 如何在 FROM 子句的参数化查询的命令行中引用 BQ 表作为参数(例如我尝试使用 @variable_table 执行的操作)?有可能吗?
  2. 除了我目前使用的方法之外,您是否知道从命令行对多个 BQ 表运行查询的其他方法?

希望这一切都有意义,并感谢您的帮助!

【问题讨论】:

  • 从您链接的文档中,“参数不能用作标识符、列名、表名或查询的其他部分的替代品。”
  • 天哪。我一定是错过了那部分。这是相当漫长的一天。感谢您的回复。
  • 我认为可能对您有用的方法是将表名注入作为常规 shell 变量(而不是查询参数)。不过,您需要确保信任它的内容,或者您​​自己构建字符串以避免 SQL 注入。
  • @ElliottBrossard - 您介意将您的评论推广为后代的答案吗?几个月前我犯了同样的错误:-)
  • 完成 :) 我想我们最近确实更新了这个主题,所以你可能在没有明确说明参数只能替换表达式之前已经看到它。

标签: sql linux command-line parameters google-bigquery


【解决方案1】:

来自您链接的文档:

参数不能用于替代标识符、列名、表名或查询的其他部分。

我认为在这种情况下可能对您有用的方法是将表名注入作为常规 shell 变量(而不是查询参数)。您需要确保信任它的内容,或者您​​自己构建字符串以避免 SQL 注入。一种方法是为表名设置硬编码常量,然后根据用户输入选择要插入到查询文本中的常量。

【讨论】:

    【解决方案2】:

    我想我会在这里发布我的示例,它仅涵盖您有关创建“动态表名”的问题,但您也可以将我的方法用于您的其他变量。我的方法是在执行 BigQuery API 调用之前直接在 python 中执行此操作,方法是利用 python 的内部时间函数(假设您希望变量是基于时间的)。

    通过 Python BQ API 创建 BigQuery 表:

    from google.colab import auth
    from datetime import datetime
    from google.cloud import bigquery
    
    auth.authenticate_user()
    now = datetime.now()
    current_time = now.strftime("%Y%m%d%H%M")
    
    project_id = '<project_id>'
    client = bigquery.Client(project=project_id)
    
    table_id = "<project_id>.<dataset_id>.table_"
    table_id = table_id + current_time
    job_config = bigquery.QueryJobConfig(destination=table_id)
    
    sql = """
    SELECT
        dataset_id,
        project_id,
        table_id,
        CASE
          WHEN type = 1 THEN 'table'
          WHEN type = 2 THEN 'view'
          WHEN type = 3 THEN 'external'
          ELSE '?'
        END AS type,
        DATE(TIMESTAMP_MILLIS(creation_time)) AS creation_date,
        TIMESTAMP_MILLIS(creation_time) AS creation_time,
        row_count,
        size_bytes,
        round(safe_divide(size_bytes, (1000*1000)),1) as size_mb,
        round(safe_divide(size_bytes, (1000*1000*1000)),3) as size_gb
    FROM (select * from `<project_id>:<dataset_id>.__TABLES__`)
    ORDER BY dataset_id, table_id asc;
    """
    
    query_job = client.query(sql, job_config=job_config)
    query_job.result()
    print("Query results loaded to the table {}".format(table_id))
    
    # Output: 
    # Query results loaded to the table <project_id>.<dataset_id>.table_202101141450
    

    您可以随意在 google colab notebook 中复制和测试它。只需填写您自己的:

    • &lt;project_id&gt;
    • &lt;dataset_id&gt;

    【讨论】:

      猜你喜欢
      • 2015-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-30
      • 1970-01-01
      • 2018-11-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多