Bigquery - 参数化存储过程中的表和列
Bigquery - parametrize tables and columns in a stored procedure
考虑一家为不同生产设施捕获传感器数据的企业。每个设施,我们创建一个聚合查询,将值平均到 5 分钟的时隙。此查询存在于一长串 with-clauses 中,并将数据写入 table(称为 aggregation_table)。
现在我的问题是:目前我们有 n 个查询 运行ning 完全 运行 相同的逻辑,唯一不同的是 table 名称(有时是列名称,但让我们暂时忽略它)。
与其管理 n 个基本相同的不同脚本,不如将其放在一个能够像这样工作的存储过程中:
CALL aggregation_query(facility_name) -> 解析该设施的不同 table,然后在不同的 with 子句中使用它们
最重要的是,我不想让这一长串子句给我最终结果,而是想将它们分成可参数化的逻辑块,例如,如果我调用上述 stored_procedure 对于设施 A,我希望能够在这些不同的函数中传递/使用此 table 名称,其中输出可以在下一个语句中重新使用(就像您对 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) 函数也可以接受这个 table_name 参数并且 return 返回一个 table 可以在下一个 with 子句(或者写入临时 table)
我认为下面的代码片段可以让您在处理过程、插入和执行立即语句时获得一些见解。
我在这里创建了一个过程,它将值插入到存在于信息模式中的 table 中。另外,作为一个值,我想 return 我使用 OUT
active_table_name 到 return 我在过程中分配的值。
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
您还可以使用循环从工作 table 中迭代记录,这样它将执行该过程,并且还能够从该过程中获取值以在某处使用 else.ie:执行删除操作的第二个程序。
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;
回顾一下,有一些限制,例如在立即执行内调用过程的可能性或在立即执行内使用立即执行,等等。我认为这些片段应该可以帮助您处理当前的情况。
对于此示例,我使用以下文档:
考虑一家为不同生产设施捕获传感器数据的企业。每个设施,我们创建一个聚合查询,将值平均到 5 分钟的时隙。此查询存在于一长串 with-clauses 中,并将数据写入 table(称为 aggregation_table)。
现在我的问题是:目前我们有 n 个查询 运行ning 完全 运行 相同的逻辑,唯一不同的是 table 名称(有时是列名称,但让我们暂时忽略它)。
与其管理 n 个基本相同的不同脚本,不如将其放在一个能够像这样工作的存储过程中:
CALL aggregation_query(facility_name) -> 解析该设施的不同 table,然后在不同的 with 子句中使用它们
最重要的是,我不想让这一长串子句给我最终结果,而是想将它们分成可参数化的逻辑块,例如,如果我调用上述 stored_procedure 对于设施 A,我希望能够在这些不同的函数中传递/使用此 table 名称,其中输出可以在下一个语句中重新使用(就像您对 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) 函数也可以接受这个 table_name 参数并且 return 返回一个 table 可以在下一个 with 子句(或者写入临时 table)
我认为下面的代码片段可以让您在处理过程、插入和执行立即语句时获得一些见解。
我在这里创建了一个过程,它将值插入到存在于信息模式中的 table 中。另外,作为一个值,我想 return 我使用 OUT
active_table_name 到 return 我在过程中分配的值。
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
您还可以使用循环从工作 table 中迭代记录,这样它将执行该过程,并且还能够从该过程中获取值以在某处使用 else.ie:执行删除操作的第二个程序。
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;
回顾一下,有一些限制,例如在立即执行内调用过程的可能性或在立即执行内使用立即执行,等等。我认为这些片段应该可以帮助您处理当前的情况。
对于此示例,我使用以下文档: