类别:

:doc:`/sql-reference/functions-semistructured`(高阶)

REDUCE

基于 Lambda 表达式中的逻辑将 数组 减少为单个值。

REDUCE 函数接受一个数组、一个初始累加器值和一个 lambda 函数。它将 lambda 函数应用于数组的每个元素,使用每个结果更新累加器。处理所有元素后,REDUCE 返回最终的累加器值。

另请参阅:

通过 Snowflake 高阶函数对数据使用 lambda 函数

语法

REDUCE( <array> , <init> , <lambda_expression> )
Copy

实参

array

包含要减少的元素的数组。这可以是半结构化数组,也可以是结构化数组。

init

初始累加器值。

lambda_expression

一个 lambda 表达式,定义每个数组元素的归约逻辑。

lambda 表达式必须按照以下语法指定:

<acc> [ <datatype> ] , <value> [ <datatype> ] -> <expr>
Copy

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;
Copy
+---------------+
| SUM_OF_VALUES |
|---------------|
|             6 |
+---------------+

本例与上例相同,但它指定了一个类型为 INT 的结构化数组:

SELECT REDUCE([1,2,3]::ARRAY(INT),
              0,
              (acc, val) -> acc + val)
  AS sum_of_values_structured;
Copy
+--------------------------+
| SUM_OF_VALUES_STRUCTURED |
|--------------------------|
|                        6 |
+--------------------------+

使用 REDUCE 函数返回数组中值的总和,并指定 10 作为初始累加器值:

SELECT REDUCE([1,2,3],
              10,
              (acc, val) -> acc + val)
  AS sum_of_values_plus_10;
Copy
+-----------------------+
| SUM_OF_VALUES_PLUS_10 |
|-----------------------|
|                    16 |
+-----------------------+

计算数组中每个值的平方和

使用 REDUCE 函数返回数组中每个值的平方和,并指定 0 作为初始累加器值:

SELECT REDUCE([1,2,3],
              0,
              (acc, val) -> acc + val * val)
  AS sum_of_squares;
Copy
+----------------+
| 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;
Copy
+-------------------------+
| SUM_OF_VALUES_SKIP_NULL |
|-------------------------|
|                      10 |
+-------------------------+

生成字符串值

使用 REDUCE 函数通过连接数组中的每个值来返回字符串值的列表:

SELECT REDUCE(['a', 'b', 'c'],
              '',
              (acc, val) -> acc || ' ' || val)
  AS string_values;
Copy
+---------------+
| STRING_VALUES |
|---------------|
|  a b c        |
+---------------+

使用数组作为累加器

使用 REDUCE 函数和 ARRAY_PREPEND 函数在 lambda 表达式的逻辑中返回一个反转输入数组顺序的数组:

SELECT REDUCE([1, 2, 3, 4],
              [],
              (acc, val) -> ARRAY_PREPEND(acc, val))
  AS reverse_order;
Copy
+---------------+
| 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;
Copy
+-------------------+
| CONDITIONAL_LOGIC |
|-------------------|
|                50 |
+-------------------+

将表格中的元素数组减少为单个值

假设您有一个名为 orders 的表,包含 order_idorder_dateorder_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;
Copy
+----------+------------+-------------------------------------------+
| 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;
Copy
+----------+------------+--------------+
| 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;
Copy
+----------+------------+-----------------------------+
| ORDER_ID | ORDER_DATE | ITEMS_SOLD                  |
|----------+------------+-----------------------------|
|        1 | 2024-01-01 | Business Printer            |
|          |            | UHD Monitor                 |
|          |            |                             |
|        2 | 2024-01-02 | Noise-canceling Headphones  |
|          |            | Laptop                      |
|          |            |                             |
+----------+------------+-----------------------------+
语言: 中文