繁体   English   中英

bigquery 类型检查运算符? 就像 Javascript 中的 typeof; 或解决方法

[英]bigquery type check operator? like typeof in Javascript; or workaround

在一个BigQuery 表的schema 不断发展的项目中,我想知道有没有一种好的方法可以通用地编写SQL 代码?

例如,版本 1 中的功能标志字段是一个简单的 BOOLEAN,但后来演变为 FLOAT 来表示 0(假)和 1(真)之间的值,然后针对每个模式修订更改为多个 BOOLEAN 的 STRUCT我也更改了表名,所以现在我有当前表v3和旧表v2和v1,旧表有历史信息有时仍然有用,而且体积很大不利于全部迁移到v3模式; 由于 bigquery 主要用作加载一次然后仅附加,或者大多数情况下只读数据库,只从旧表查询就足够了; 使用表名通配符我可以在单个查询中查询所有表,但不确定如何处理不同的输入类型,是否有动态类型检查功能来编写查询 SQL,如 Javascript 中的这种typeof运算符:?

CASE typeof feature
  WHEN "BOOLEAN" THEN ... # handle v1
  WHEN "FLOAT"   THEN ... # handle v2
  WHEN "STRUCT"  THEN ... # handle v3
  WHEN ...
  ELSE
END

或者你会建议解决什么问题? 如果项目的性质具有不断发展的模式(由于快速变化的需求或许多其他常见原因)

FORMAT('%T', obj)将任何键入的值转换为文字字符串。 可用于实现 SQL UDF 中的typeof函数。

CREATE TEMP FUNCTION typeof_literal(input STRING)
AS (
      CASE
        -- Process NUMERIC, DATE, DATETIME, TIME, TIMESTAMP,
        WHEN REGEXP_CONTAINS(input, r'^[A-Z]+ "') THEN REGEXP_EXTRACT(input, r'^([A-Z]+) "')
        WHEN REGEXP_CONTAINS(input, r'^-?[0-9]*$') THEN 'INT64'
        WHEN REGEXP_CONTAINS(input, r'^(-?[0-9]+[.e].*|CAST\("([^"]*)" AS FLOAT64\))$') THEN 'FLOAT64'
        WHEN input IN ('true', 'false') THEN 'BOOL'
        WHEN input LIKE '"%' THEN 'STRING'
        WHEN input LIKE 'b"%' THEN 'BYTES'
        WHEN input LIKE '[%' THEN 'ARRAY'
        WHEN REGEXP_CONTAINS(input, r'^(STRUCT)?\(') THEN 'STRUCT'
        WHEN input LIKE 'ST_%' THEN 'GEOGRAPHY'
        WHEN input = 'NULL' THEN 'NULL'
      ELSE
      'UNKNOWN'
    END );

CREATE TEMP FUNCTION typeof(input ANY TYPE)
AS ( typeof_literal(FORMAT('%T', input)) );

-- You can pass any type value to typeof function
SELECT typeof(CURRENT_TIMESTAMP());
-- result: "TIMESTAMP"
SELECT typeof(STRUCT(1, 2, 3));
-- result: "STRUCT"

详尽的测试和结果放在要点中,因为它太长了。

更新

您可以使用基于社区的公共 UDF bqutil.fn.typeof

CASE bqutil.fn.typeof(feature)
  WHEN "BOOLEAN" THEN ... # handle v1
  WHEN "FLOAT"   THEN ... # handle v2
  WHEN "STRUCT"  THEN ... # handle v3
  WHEN ...
  ELSE
END

注意:BigQuery 在执行查询之前会进行类型检查,因此THEN子句中的表达式必须在所有WHEN-THEN对中都有效。

或者你会建议解决什么问题?

所以,换句话说你的想法 - 你正在考虑来自具有不同模式的不同表的 UNION ALL 。 不幸的是,由于模式不同,这不会成功!

我推荐以下解决方法:
您需要为每个版本创建一个视图,以使每个视图的架构相同。 请参见下面的示例

#standardSQL
WITH table_v1 AS (
  SELECT 1 AS id, TRUE AS feature UNION ALL
  SELECT 2 AS id, FALSE AS feature 
),
table_v2 AS (
  SELECT 3 AS id, 0.2 AS feature UNION ALL
  SELECT 4 AS id, 0.8 AS feature 
),
table_v3 AS (
  SELECT 5 AS id, STRUCT<x BOOL, y bool, z bool>(TRUE, FALSE, TRUE) AS feature UNION ALL
  SELECT 6 AS id, (TRUE, TRUE, TRUE) AS feature 
),
view_v1 AS (
  SELECT id, feature 
  FROM table_v1  
),
view_v2 AS ( 
  SELECT id, CASE WHEN feature < 0.5 THEN TRUE ELSE FALSE END AS feature -- handle v2
  FROM table_v2 
),
view_v3 AS (
  SELECT id, feature.x OR feature.y OR feature.z AS feature -- handle v3
  FROM table_v3
),
table_all AS (
  SELECT * FROM view_v1 UNION ALL
  SELECT * FROM view_v2 UNION ALL
  SELECT * FROM view_v3 
)
SELECT *
FROM table_all
WHERE feature
-- ORDER BY id  

保存视图时 - 您将能够对这些视图使用通配符

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM