- 类别:
:doc:`/sql-reference/functions-semistructured`(高阶)
REDUCE¶
基于 Lambda 表达式中的逻辑将 数组 减少为单个值。
REDUCE 函数接受一个数组、一个初始累加器值和一个 lambda 函数。它将 lambda 函数应用于数组的每个元素,使用每个结果更新累加器。处理所有元素后,REDUCE 返回最终的累加器值。
语法¶
REDUCE( <array> , <init> , <lambda_expression> )
实参¶
array
包含要减少的元素的数组。这可以是半结构化数组,也可以是结构化数组。
init
初始累加器值。
lambda_expression
一个 lambda 表达式,定义每个数组元素的归约逻辑。
lambda 表达式必须按照以下语法指定:
<acc> [ <datatype> ] , <value> [ <datatype> ] -> <expr>
acc
实参是累加器,value
实参是当前正在处理的数组元素。
返回¶
此函数可以返回任何数据类型的值。
如果输入数组为空,则函数返回累加器的初始值。
函数在以下情况下返回 NULL:
输入数组是 NULL。
累加器的初始值是 NULL。
lambda 函数返回 NULL。
使用说明¶
显式指定 lambda
value
实参的数据类型时,在 lambda 调用之前,数组元素将被强制转换为指定类型。有关强制转换的信息,请参阅 数据类型转换。类型检查确保累加器的初始值、累加器的 lambda 实参以及 lambda 执行的返回值都具有相同的逻辑和物理类型。如果 类型转换 用来满足此要求,则使用三者中最大的物理类型。
value
实参可以具有中间 NULL 值。有关示例,请参阅 跳过数组中的 NULL 值。
示例¶
以下示例使用 REDUCE 函数。
计算数组中值的总和¶
使用 REDUCE 函数返回数组中值的总和,并指定 0
作为初始累加器值:
SELECT REDUCE([1,2,3],
0,
(acc, val) -> acc + val)
AS sum_of_values;
+---------------+
| SUM_OF_VALUES |
|---------------|
| 6 |
+---------------+
本例与上例相同,但它指定了一个类型为 INT 的结构化数组:
SELECT REDUCE([1,2,3]::ARRAY(INT),
0,
(acc, val) -> acc + val)
AS sum_of_values_structured;
+--------------------------+
| SUM_OF_VALUES_STRUCTURED |
|--------------------------|
| 6 |
+--------------------------+
使用 REDUCE 函数返回数组中值的总和,并指定 10
作为初始累加器值:
SELECT REDUCE([1,2,3],
10,
(acc, val) -> acc + val)
AS sum_of_values_plus_10;
+-----------------------+
| SUM_OF_VALUES_PLUS_10 |
|-----------------------|
| 16 |
+-----------------------+
计算数组中每个值的平方和¶
使用 REDUCE 函数返回数组中每个值的平方和,并指定 0
作为初始累加器值:
SELECT REDUCE([1,2,3],
0,
(acc, val) -> acc + val * val)
AS sum_of_squares;
+----------------+
| SUM_OF_SQUARES |
|----------------|
| 14 |
+----------------+
跳过数组中的 NULL 值¶
在这个示例中,array
实参包括 NULL 值。将数组传递给 REDUCE 函数时,累加器将具有中间 NULL 值。
使用 REDUCE 函数返回数组中值的总和,并在 lambda 表达式的逻辑中使用 IFNULL 函数跳过数组中的 NULL 值。lambda 表达式使用 IFNULL 函数来处理使用以下逻辑的数组中的每个值:
如果
acc + val
是 NULL,那么它变成acc + 0
。如果
acc + val
不是 NULL,那么它变成acc + val
。
运行查询:
SELECT REDUCE([1,NULL,2,NULL,3,4],
0,
(acc, val) -> IFNULL(acc + val, acc + 0))
AS SUM_OF_VALUES_SKIP_NULL;
+-------------------------+
| SUM_OF_VALUES_SKIP_NULL |
|-------------------------|
| 10 |
+-------------------------+
生成字符串值¶
使用 REDUCE 函数通过连接数组中的每个值来返回字符串值的列表:
SELECT REDUCE(['a', 'b', 'c'],
'',
(acc, val) -> acc || ' ' || val)
AS string_values;
+---------------+
| STRING_VALUES |
|---------------|
| a b c |
+---------------+
使用数组作为累加器¶
使用 REDUCE 函数和 ARRAY_PREPEND 函数在 lambda 表达式的逻辑中返回一个反转输入数组顺序的数组:
SELECT REDUCE([1, 2, 3, 4],
[],
(acc, val) -> ARRAY_PREPEND(acc, val))
AS reverse_order;
+---------------+
| REVERSE_ORDER |
|---------------|
| [ |
| 4, |
| 3, |
| 2, |
| 1 |
| ] |
+---------------+
使用条件逻辑¶
使用 REDUCE 函数和 IFF 函数在 lambda 表达式(类似于 if-then
表达式)的逻辑中执行基于条件逻辑的操作。此示例在 lambda 表达式中使用以下逻辑:
如果数组值小于七,则将其平方并将其添加到累加器中。
如果数组值大于或等于七,则将其添加到累加器中,而不进行平方。
SELECT REDUCE([5,10,15],
0,
(acc, val) -> IFF(val < 7, acc + val * val, acc + val))
AS conditional_logic;
+-------------------+
| CONDITIONAL_LOGIC |
|-------------------|
| 50 |
+-------------------+
将表格中的元素数组减少为单个值¶
假设您有一个名为 orders
的表,包含 order_id
、order_date
和 order_detail
列。order_detail
列是包含行项目、其购买数量和小计的数组。该表包含两行数据。以下 SQL 语句会创建此表并插入行:
CREATE OR REPLACE TABLE orders AS
SELECT 1 AS order_id, '2024-01-01' AS order_date, [
{'item':'UHD Monitor', 'quantity':3, 'subtotal':1500},
{'item':'Business Printer', 'quantity':1, 'subtotal':1200}
] AS order_detail
UNION SELECT 2 AS order_id, '2024-01-02' AS order_date, [
{'item':'Laptop', 'quantity':5, 'subtotal':7500},
{'item':'Noise-canceling Headphones', 'quantity':5, 'subtotal':1000}
] AS order_detail;
SELECT * FROM orders;
+----------+------------+-------------------------------------------+
| ORDER_ID | ORDER_DATE | ORDER_DETAIL |
|----------+------------+-------------------------------------------|
| 1 | 2024-01-01 | [ |
| | | { |
| | | "item": "UHD Monitor", |
| | | "quantity": 3, |
| | | "subtotal": 1500 |
| | | }, |
| | | { |
| | | "item": "Business Printer", |
| | | "quantity": 1, |
| | | "subtotal": 1200 |
| | | } |
| | | ] |
| 2 | 2024-01-02 | [ |
| | | { |
| | | "item": "Laptop", |
| | | "quantity": 5, |
| | | "subtotal": 7500 |
| | | }, |
| | | { |
| | | "item": "Noise-canceling Headphones", |
| | | "quantity": 5, |
| | | "subtotal": 1000 |
| | | } |
| | | ] |
+----------+------------+-------------------------------------------+
使用 REDUCE 函数返回每个订单中所有项目的小计总和:
SELECT order_id,
order_date,
REDUCE(o.order_detail,
0,
(acc, val) -> acc + val:subtotal) subtotal_sum
FROM orders o;
+----------+------------+--------------+
| ORDER_ID | ORDER_DATE | SUBTOTAL_SUM |
|----------+------------+--------------|
| 1 | 2024-01-01 | 2700 |
| 2 | 2024-01-02 | 8500 |
+----------+------------+--------------+
使用 REDUCE 函数返回每个订单中销售的项目列表:
SELECT order_id,
order_date,
REDUCE(o.order_detail,
'',
(acc, val) -> val:item || '\n' || acc) items_sold
FROM orders o;
+----------+------------+-----------------------------+
| ORDER_ID | ORDER_DATE | ITEMS_SOLD |
|----------+------------+-----------------------------|
| 1 | 2024-01-01 | Business Printer |
| | | UHD Monitor |
| | | |
| 2 | 2024-01-02 | Noise-canceling Headphones |
| | | Laptop |
| | | |
+----------+------------+-----------------------------+