如何在 BigQuery 中实现通用 Oracle DECODE 函数?
Posted
技术标签:
【中文标题】如何在 BigQuery 中实现通用 Oracle DECODE 函数?【英文标题】:How to implement generic Oracle DECODE function in BigQuery? 【发布时间】:2019-09-25 20:37:13 【问题描述】:我正在考虑将 Oracle DECODE 函数实现为 UDF。
下面是外部功能 https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions040.htm
以下是 Oracle 中解码的外部功能和语法:
Oracle:
DECODE( <expr> , <search1> , <result1> [ , <search2> , <result2> ... ] [ , <default> ] )
SELECT product_id,
DECODE (warehouse_id, 1, 'Southlake',
2, 'San Francisco',
3, 'New Jersey',
4, 'Seattle',
'Non domestic')
"Location of inventory" FROM inventories;
首先,对于 BigQuery UDF SQL 或 javascript,对于 BigQuery UDF,当您定义 UDF 函数时,您需要知道您接受和输入的参数数量。当您定义 SQL UDF 函数时,您还可以接受任何类型的数组,但我不确定它是否可以工作并且 SQL UDF 是否可以使用数组执行我们想要的操作。似乎基于 Javascript UDF 文档,所有参数都被命名和键入并且预先知道。
有没有办法使用 BigQuery UDF 来实现这一点,它必须像 Oracle 解码一样是动态的,并且适合你放在它前面的任何场景,而不是知道你在解码什么的静态
【问题讨论】:
【参考方案1】:以下是 BigQuery 标准 SQL
CREATE TEMP FUNCTION DECODE(expr ANY TYPE, map ANY TYPE, `default` ANY TYPE ) AS ((
IFNULL((SELECT result FROM UNNEST(map) WHERE search = expr), `default`)
));
你可以使用下面的例子来看看它是如何工作的
#standardSQL
CREATE TEMP FUNCTION DECODE(expr ANY TYPE, map ANY TYPE, `default` ANY TYPE ) AS ((
IFNULL((SELECT result FROM UNNEST(map) WHERE search = expr), `default`)
));
WITH `project.dataset.inventories` AS (
SELECT 1 product_id, 4 warehouse_id UNION ALL
SELECT 2, 2 UNION ALL
SELECT 3, 5
)
SELECT product_id, warehouse_id,
DECODE(warehouse_id,
[STRUCT<search INT64, result STRING>
(1,'Southlake'),
(2,'San Francisco'),
(3,'New Jersey'),
(4,'Seattle')
], 'Non domestic') AS `Location_of_inventory`
FROM `project.dataset.inventories`
结果
Row product_id warehouse_id Location_of_inventory
1 1 4 Seattle
2 2 2 San Francisco
3 3 5 Non domestic
另一个使用例子是:
#standardSQL
CREATE TEMP FUNCTION DECODE(expr ANY TYPE, map ANY TYPE, `default` ANY TYPE ) AS ((
IFNULL((SELECT result FROM UNNEST(map) WHERE search = expr), `default`)
));
WITH `project.dataset.inventories` AS (
SELECT 1 product_id, 4 warehouse_id UNION ALL
SELECT 2, 2 UNION ALL
SELECT 3, 5
), map AS (
SELECT 1 search, 'Southlake' result UNION ALL
SELECT 2, 'San Francisco' UNION ALL
SELECT 3, 'New Jersey' UNION ALL
SELECT 4, 'Seattle'
)
SELECT product_id, warehouse_id,
DECODE(warehouse_id, kv, 'Non domestic') AS `Location_of_inventory`
FROM `project.dataset.inventories`,
(SELECT ARRAY_AGG(STRUCT(search, result)) AS kv FROM map) arr
输出相同
更新到地址 - “对于可重用的 UDF,不必命名字段使其更接近 Oracle 的实现。”
CREATE TEMP FUNCTION DECODE(expr ANY TYPE, map ANY TYPE, `default` ANY TYPE ) AS (
IFNULL((
SELECT result FROM (
SELECT NULL AS search, NULL AS result UNION ALL SELECT * FROM UNNEST(map)
)
WHERE search = expr
), `default`)
);
所以现在 - 之前的示例可以在没有显式命名字段的情况下使用,如下例所示
#standardSQL
CREATE TEMP FUNCTION DECODE(expr ANY TYPE, map ANY TYPE, `default` ANY TYPE ) AS (
IFNULL((
SELECT result FROM (
SELECT NULL AS search, NULL AS result UNION ALL SELECT * FROM UNNEST(map)
)
WHERE search = expr
), `default`)
);
WITH `project.dataset.inventories` AS (
SELECT 1 product_id, 4 warehouse_id UNION ALL
SELECT 2, 2 UNION ALL
SELECT 3, 5
)
SELECT product_id, warehouse_id,
DECODE(warehouse_id,
[ (1,'Southlake'),
(2,'San Francisco'),
(3,'New Jersey'),
(4,'Seattle')
], 'Non domestic') AS `Location_of_inventory`
FROM `project.dataset.inventories`
还是和之前一样的输出
【讨论】:
以上是关于如何在 BigQuery 中实现通用 Oracle DECODE 函数?的主要内容,如果未能解决你的问题,请参考以下文章
在 mapreduce 中实现 BigQuery UDF 作为地图的动机是啥?
如何在 Swift 中实现一个管理 UserDefaults 的键值对的通用结构?
如何在 Spring Boot 中实现通用 JPA 存储库 - 它可以自动装配到任何实体/类类型的 Spring 服务中