类别:

:doc:`/sql-reference/functions-window-syntax`(排名)

FIRST_VALUE

返回一组有序值中的第一个值。

另请参阅:

LAST_VALUENTH_VALUE

语法

FIRST_VALUE( <expr> ) [ { IGNORE | RESPECT } NULLS ]
  OVER ( [ PARTITION BY <expr1> ] ORDER BY <expr2>  [ { ASC | DESC } ] [ NULLS { FIRST | LAST } ] [ <window_frame> ] )

有关 window_frame 语法的详细信息,请参阅 窗口函数的语法和用法

实参

expr

确定返回值的表达式。

expr1

用于对行进行分区的表达式。您可以指定单个表达式或以逗号分隔的表达式列表。例如:

PARTITION BY column_1, column_2
expr2

用于对行进行排序的表达式。您可以指定单个表达式或以逗号分隔的表达式列表。例如:

ORDER BY column_3, column_4
{ IGNORE | RESPECT } NULLS

expr 包含 NULL 值时,是忽略还是遵照 NULL 值:

  • IGNORE NULLS 返回第一个非 NULL 值。

  • 如果 RESPECT NULLS 是表达式中的第一个值,则返回一个 NULL 值。

默认值:RESPECT NULLS

使用说明

  • 此函数是与排名相关的函数,因此它必须指定一个窗口。窗口子句由以下分子句组成:

    • PARTITION BY expr1 分子句(可选)。

    • ORDER BY expr2 分子句(必需)。有关其他受支持的排序选项(排序顺序、NULL 值排序等)的详细信息,请参阅 ORDER BY 子句的文档,该子句遵循相同的规则。

    • window_frame 分子句(可选)。

  • 仅当 ORDER BY 子句中的键使每一行都唯一时,窗口中行的顺序(以及查询结果)才是完全确定的。请参考以下示例:

    ... OVER (PARTITION BY p ORDER BY o COLLATE 'lower') ...
    

    如果任何分区包含相同的列 o 值,或者在不区分大小写的比较中相同,则查询结果可能会有所不同。

  • OVER 子句中的 ORDER BY 子句只控制窗口中行的顺序,而不控制整个查询输出中行的顺序。若要控制输出顺序,请在查询的最外层使用单独的 ORDER BY 子句。

  • 可选的 window_frame 指定计算函数的窗口中行的子集。如果未指定 window_frame,默认为整个窗口:

    ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING

    请注意,这偏离了 ANSI 标准,该标准为窗口框架指定了以下默认值:

    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW

有关 window_frame 语法的详细信息,请参阅 窗口函数的语法和用法

示例

此示例显示了一个查询,该查询使用 FIRST_VALUE 函数查找每个类别中最便宜的菜单项。该查询包含两个 ORDER BY 子句,一个用于控制每个分区中行的顺序,另一个用于控制整个查询的输出顺序。要创建和加载此示例中使用的表,请参阅 创建并加载 menu_items 表

SELECT menu_category, menu_item_name, menu_price_usd,
       FIRST_VALUE(menu_item_name) OVER (PARTITION BY menu_category ORDER BY menu_price_usd) AS cheapest_item
  FROM menu_items
  WHERE menu_category IN ('Beverage', 'Dessert', 'Snack')
  ORDER BY menu_category, menu_price_usd
  LIMIT 12;
+---------------+--------------------+----------------+---------------+
| MENU_CATEGORY | MENU_ITEM_NAME     | MENU_PRICE_USD | CHEAPEST_ITEM |
|---------------+--------------------+----------------+---------------|
| Beverage      | Bottled Water      |           2.00 | Bottled Water |
| Beverage      | Iced Tea           |           3.00 | Bottled Water |
| Beverage      | Bottled Soda       |           3.00 | Bottled Water |
| Beverage      | Lemonade           |           3.50 | Bottled Water |
| Dessert       | Popsicle           |           3.00 | Popsicle      |
| Dessert       | Ice Cream Sandwich |           4.00 | Popsicle      |
| Dessert       | Mango Sticky Rice  |           5.00 | Popsicle      |
| Dessert       | Sugar Cone         |           6.00 | Popsicle      |
| Dessert       | Waffle Cone        |           6.00 | Popsicle      |
| Dessert       | Two Scoop Bowl     |           7.00 | Popsicle      |
| Snack         | Spring Mix Salad   |           6.00 | Fried Pickles |
| Snack         | Fried Pickles      |           6.00 | Fried Pickles |
+---------------+--------------------+----------------+---------------+

以下示例也使用用于比较三个相关函数的 menu_items 表:FIRST_VALUE、NTH_VALUELAST_VALUE

  • 该查询创建一个三行宽的滑动窗口框架,其中包含:

    • 当前行前面的行。

    • 当前行。

    • 当前行后面的行。

  • 调用 2 中的 NTH_VALUE(menu_price_usd, 2) 指定了窗口框架中的第二行(在本例中也是当前行)。

  • 当前行是窗口框架中的第一行时,没有前面的行可以引用,因此 FIRST_VALUE 为该行返回 NULL。

  • 框架边界有时会超出分区中的行,但不存在的行不包括在窗口函数计算中。例如,若当前行是分区中的第一行而窗口框架 ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING,没有前一行可供引用,则 FIRST_VALUE 函数返回分区中第一行的值。

  • 鉴于表中的数据,所有三个函数的结果永远不匹配。这些函数为框架中的每行选择 第一个最后一个第 n 个 值,并且值的选择分别适用于每个分区。

SELECT menu_category, menu_item_name, menu_price_usd,
       FIRST_VALUE(menu_price_usd) OVER (PARTITION BY menu_category ORDER BY menu_price_usd
         ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS first_val,
       NTH_VALUE(menu_price_usd, 2) OVER (PARTITION BY menu_category ORDER BY menu_price_usd
         ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS nth_val,
       LAST_VALUE(menu_price_usd) OVER (PARTITION BY menu_category ORDER BY menu_price_usd
         ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS last_val
  FROM menu_items
  WHERE menu_category = 'Dessert'
  ORDER BY menu_price_usd;
+---------------+--------------------+----------------+-----------+---------+----------+
| MENU_CATEGORY | MENU_ITEM_NAME     | MENU_PRICE_USD | FIRST_VAL | NTH_VAL | LAST_VAL |
|---------------+--------------------+----------------+-----------+---------+----------|
| Dessert       | Popsicle           |           3.00 |      3.00 |    4.00 |     4.00 |
| Dessert       | Ice Cream Sandwich |           4.00 |      3.00 |    4.00 |     5.00 |
| Dessert       | Mango Sticky Rice  |           5.00 |      4.00 |    5.00 |     6.00 |
| Dessert       | Sugar Cone         |           6.00 |      6.00 |    6.00 |     7.00 |
| Dessert       | Waffle Cone        |           6.00 |      5.00 |    6.00 |     6.00 |
| Dessert       | Two Scoop Bowl     |           7.00 |      6.00 |    7.00 |     7.00 |
+---------------+--------------------+----------------+-----------+---------+----------+

此示例演示了 IGNORE NULLS 和 RESPECT NULLS 之间的区别。示例数据中包含成本值为 NULL 的行。使用默认值 RESPECT NULLS 行为,如果有序分区中的第一行具有 NULL 值,FIRST_VALUE 返回 NULL。使用 IGNORE NULLS,FIRST_VALUE 跳过 NULL 值并返回第一个非 NULL 值。

SELECT item_name, item_cost, item_price,
       FIRST_VALUE(item_cost) RESPECT NULLS
         OVER (ORDER BY item_price) AS first_cost_respect,
       FIRST_VALUE(item_cost) IGNORE NULLS
         OVER (ORDER BY item_price) AS first_cost_ignore
  FROM VALUES
    ('Pretzel', NULL, 3.00),
    ('Corn Dog', NULL, 4.00),
    ('Hot Dog', 1.50, 5.00),
    ('Sandwich', 2.50, 6.00)
  AS menu(item_name, item_cost, item_price)
  ORDER BY item_price;
+-----------+-----------+------------+--------------------+-------------------+
| ITEM_NAME | ITEM_COST | ITEM_PRICE | FIRST_COST_RESPECT | FIRST_COST_IGNORE |
|-----------+-----------+------------+--------------------+-------------------|
| Pretzel   |      NULL |       3.00 |               NULL |              1.50 |
| Corn Dog  |      NULL |       4.00 |               NULL |              1.50 |
| Hot Dog   |      1.50 |       5.00 |               NULL |              1.50 |
| Sandwich  |      2.50 |       6.00 |               NULL |              1.50 |
+-----------+-----------+------------+--------------------+-------------------+