⌘+k ctrl+k
1.1.3 (stable)
Search Shortcut cmd + k | ctrl + k
CREATE MACRO Statement

CREATE MACRO 语句可以在目录中创建一个标量或表宏(函数)。 宏可能只是一个单一的 SELECT 语句(类似于 VIEW),但它具有接受参数的优势。

对于一个标量宏,CREATE MACRO 后面跟着宏的名称,以及可选的一组括号内的参数。接下来是关键字 AS,然后是宏的文本。设计上,标量宏只能返回单个值。 对于一个表宏,语法与标量宏类似,除了 AS 被替换为 AS TABLE。表宏可以返回任意大小和形状的表。

如果一个MACRO是临时的,它只能在同一个数据库连接中使用,并且在连接关闭时被删除。

Examples

标量宏

创建一个宏,用于添加两个表达式(ab):

CREATE MACRO add(a, b) AS a + b;

为case表达式创建一个宏:

CREATE MACRO ifelse(a, b, c) AS CASE WHEN a THEN b ELSE c END;

创建一个执行子查询的宏:

CREATE MACRO one() AS (SELECT 1);

创建一个带有公共表表达式的宏。 请注意,参数名称优先于列名称。要解决这个问题,请使用表名来消除歧义。

CREATE MACRO plus_one(a) AS (WITH cte AS (SELECT 1 AS a) SELECT cte.a + a FROM cte);

宏依赖于模式,并且有一个别名,FUNCTION

CREATE FUNCTION main.my_avg(x) AS sum(x) / count(x);

创建一个带有默认常量参数的宏:

CREATE MACRO add_default(a, b := 5) AS a + b;

创建一个宏 arr_append(功能等同于 array_append):

CREATE MACRO arr_append(l, e) AS list_concat(l, list_value(e));

表格宏

创建一个没有参数的表宏:

CREATE MACRO static_table() AS TABLE
    SELECT 'Hello' AS column1, 'World' AS column2;

创建一个带有参数的表宏(参数可以是任何类型):

CREATE MACRO dynamic_table(col1_value, col2_value) AS TABLE
    SELECT col1_value AS column1, col2_value AS column2;

创建一个返回多行的表宏。如果它已经存在,它将被替换,并且它是临时的(当连接结束时将自动删除):

CREATE OR REPLACE TEMP MACRO dynamic_table(col1_value, col2_value) AS TABLE
    SELECT col1_value AS column1, col2_value AS column2
    UNION ALL
    SELECT 'Hello' AS col1_value, 456 AS col2_value;

将参数作为列表传递:

CREATE MACRO get_users(i) AS TABLE
    SELECT * FROM users WHERE uid IN (SELECT unnest(i));

以下是如何使用get_users表宏的示例:

CREATE TABLE users AS
    SELECT *
    FROM (VALUES (1, 'Ada'), (2, 'Bob'), (3, 'Carl'), (4, 'Dan'), (5, 'Eve')) t(uid, name);
SELECT * FROM get_users([1, 5]);

要在任意表上定义宏,请使用query_table 函数。例如,以下宏计算表上的列校验和:

CREATE MACRO checksum(table_name) AS TABLE
    SELECT bit_xor(md5_number(COLUMNS(*)::VARCHAR))
    FROM query_table(table_name);

CREATE TABLE tbl AS SELECT unnest([42, 43]) AS x, 100 AS y;
SELECT * FROM checksum('tbl');

重载

可以根据宏接受的参数数量来重载宏,这适用于标量和表宏。

通过提供重载,我们可以同时拥有add_x(a, b)add_x(a, b, c),它们具有不同的函数体。

CREATE MACRO add_x
    (a, b) AS a + b,
    (a, b, c) AS a + b + c;
SELECT
    add_x(21, 42) AS two_args,
    add_x(21, 42, 21) AS three_args;
two_args three_args
63 84

Syntax

宏允许您为表达式的组合创建快捷方式。

CREATE MACRO add(a) AS a + b;
Binder Error: Referenced column "b" not found in FROM clause!

这行得通:

CREATE MACRO add(a, b) AS a + b;

使用示例:

SELECT add(1, 2) AS x;
x
3

然而,这失败了:

SELECT add('hello', 3);
Binder Error: Could not choose a best candidate function for the function call "+(STRING_LITERAL, INTEGER_LITERAL)". In order to select one, please add explicit type casts.
    Candidate functions:
    +(DATE, INTEGER) -> DATE
    +(INTEGER, INTEGER) -> INTEGER

宏可以有默认参数。 与某些语言不同,默认参数在调用宏时必须命名。

b 是一个默认参数:

CREATE MACRO add_default(a, b := 5) AS a + b;

以下将得到42:

SELECT add_default(37);

以下将抛出错误:

SELECT add_default(40, 2);
Binder Error: Macro function 'add_default(a)' requires a single positional argument, but 2 positional arguments were provided.

默认参数必须通过以下方式赋值使用:

SELECT add_default(40, b := 2) AS x;
x
42

然而,以下操作失败:

SELECT add_default(b := 2, 40);
Binder Error: Positional parameters cannot come after parameters with a default value!

默认参数的顺序无关紧要:

CREATE MACRO triple_add(a, b := 5, c := 10) AS a + b + c;
SELECT triple_add(40, c := 1, b := 1) AS x;
x
42

当使用宏时,它们会被展开(即替换为原始表达式),并且展开表达式中的参数会被替换为提供的参数。逐步进行:

上面定义的add宏在查询中使用:

SELECT add(40, 2) AS x;

在内部,add 被替换为其定义 a + b

SELECT a + b; AS x

然后,参数被提供的参数替换:

SELECT 40 + 2 AS x;

Limitations

使用命名参数

目前,位置宏参数只能按位置使用,命名参数只能通过提供其名称来使用。因此,以下内容将无法工作:

CREATE MACRO my_macro(a, b := 42) AS (a + b);
SELECT my_macro(32, 52);
Binder Error: Macro function 'my_macro(a)' requires a single positional argument, but 2 positional arguments were provided.

使用子查询宏

如果MACRO被定义为子查询,则不能在表函数中调用。DuckDB将返回以下错误:

Binder Error: Table function cannot contain subqueries

重载

宏函数的重载必须在创建时设置,不可能在不先移除第一个定义的情况下,用相同的名称定义两次宏。