1

考虑一个为不同生产设施捕获传感器数据的企业。每个设施,我们创建一个聚合查询,将值平均到 5 分钟的时间段。此查询存在于一长串 with 子句中,并将数据写入表(称为aggregation_table)。

现在我的问题是:目前我们有 n 个查询运行,它们运行完全相同的逻辑,唯一不同的是表名(有时是列名,但现在让我们忽略它)。

我不想管理 n 个基本相同的不同脚本,而是想将它放在一个能够像这样工作的存储过程中:

CALL aggregation_query(facility_name) -> 为该设施解析不同的表,然后在不同的 with 子句中使用它们

最重要的是,我不想有这么长的一组子句来给我最终结果,我想将它们分成可参数化的逻辑块,例如,如果我为设施 A 调用上述存储过程,我希望能够在这些不同的函数中传递/使用这个表名,输出可以在下一个语句中重复使用(就像你对 with 子句所做的那样)。

关于我为什么要将其分成可重用块的另一个论点是因为我们在此聚合查询上有许多“派生”,例如用于管理历史数据、更正数据或将传感器数据置于另一个聚合级别。随着这些变得过于复杂,管理它们要容易得多,而不必每次都复制粘贴和调整它们。

在当前设置中,知道我仅有权使用普通 BigQuery 可能很有用,因为我的团队不允许访问 CI/CD/调度和存储库。(这意味着我无法通过部署 n 个不同版本的过程和功能的 CI/CD 来解决问题)

所以最后,我想只使用 bigquery 得到这样的结果:

CREATE OR REPLACE PROCEDURE
  `aggregation_function`()
BEGIN
DECLARE
  tablename STRING;
DECLARE
  active_table_name STRING; ##get list OF tables CREATE TEMP TABLE tableNames AS
SELECT
  table_catalog,
  table_schema,
  table_name
FROM
  `catalog.schema.INFORMATION_SCHEMA.TABLES`
WHERE
  table_name = tablename;
WHILE
  (
  SELECT
    COUNT(*)
  FROM
    tableNames) >= 1 DO ##build dataset + TABLE name
SET
  active_table_name = CONCAT('`',table_catalog,'.',table_schema,'.' ,table_name,'`'); ##use concat TO build string AND execute
EXECUTE IMMEDIATE '''
INSERT INTO
  `aggregation_table_for_facility` (timeslot, sensor_name, AVG_VALUE )
WITH
  STEP_1 AS (
  SELECT
    *
  FROM
    my_table_function_step_1(active_table_name,
      parameter1,
      parameter2) ),
  STEP_2 AS (
  SELECT
    *
  FROM
    my_table_function_step_2(STEP_1,
      parameter1,
      parameter2) )
  SELECT * FROM STEP_2
  '''
USING active_table_name as active_table_name;
DELETE
FROM
  tableNames
WHERE
  table_name = tablename;
END WHILE
  ;
END
  ;

我希望有人可以在标准 SQL / Bigquery 中制作一个关于我如何做到这一点的片段,所以基本上:

  • 接受字符串变量并能够将其用作表的存储过程(在上述方法中部分解决,但不确定是否有更好的方法)

  • (table) 函数,该函数也能够接受这个 table_name 参数并返回一个可以在下一个 with 子句中使用的表(或者写入临时表)

4

1 回答 1

0

我认为下面的代码片段应该在处理过程、插入和执行立即语句时为您提供一些见解。

在这里,我正在创建一个过程,它将值插入到信息模式中存在的表中。此外,作为我想要返回的值,我使用OUT active_table_name来返回我在过程中分配的值。

CREATE OR REPLACE PROCEDURE `project-id.dataset`.custom_function(tablename STRING,OUT active_table_name STRING)
BEGIN
 
DECLARE query STRING; 

SET active_table_name= (SELECT CONCAT('`',table_catalog,'.',table_schema,'.' ,table_name,'`')
                        FROM `project-id.dataset.INFORMATION_SCHEMA.TABLES`
                        WHERE table_name = tablename);

#multine query can be handled by using ''' or """ 
Set query = 
'''
insert into %s (string_field_0,string_field_1,string_field_2,string_field_3,string_field_4,int64_field_5)
with custom_query as (
   select string_field_0,string_field_2,'169 BestCity',string_field_3,string_field_4,55677 from %s limit 1
)
select * from custom_query;
''';

# querys must perform operations and must be the last thing to perform
# pass parameters using format 
execute immediate (format(query,active_table_name,active_table_name));

END

您还可以使用循环来迭代工作表中的槽记录,以便它执行该过程并且还能够从该过程中获取值以在其他地方使用。即:执行删除操作的第二个过程

DECLARE tablename STRING; 
DECLARE out_value STRING; 

FOR record IN
  (SELECT tablename from `my-project-id.dataset.table`)
DO 
  SET tablename = record.tablename;
  LOOP
    call `project-id.dataset`.custom_function(tablename,out_value);
    select out_value;
  END LOOP; 
END FOR;

回顾一下,有一些限制,例如可以在执行立即数中调用过程或在执行立即数中使用执行立即数,仅举几例。我认为这些片段应该可以帮助您处理当前的情况。

对于此示例,我使用以下文档:

于 2022-02-07T16:11:17.827 回答