我最喜欢DuckDB的一点是:创新式SQL语法。最近的一个发现(至少对我来说)是,可以使用点操作符将函数链接起来,就像在许多通用编程语言中一样。在本文中,我们将探索该功能。
从嵌套查询开始

首先从嵌套查询语句开始:
FROM (SELECT unnest(range(1,50,5)) AS num)
SELECT
num,
factorial(
CAST(
log2(
power(
sqrt(num),
3
)
) AS INTEGER
)
) AS val;
这个查询是做什么的?对于从1到50的数字,以5为步:
- 计算平方根
- 把该值的三次方
- 计算该值的对数
- 将其转换为整数
- 最后计算阶乘
上面代码相当难以阅读,如果没有在单独行上格式化会更难懂。你必须从中间开始,然后仔细向外扩展。
链式调用
我发现从左到右阅读代码要容易得多,这就是函数链让我们做的。它有效地改写了:
## 一般调用
fn(arg1, arg2, arg3, ...)
## 链式调用
arg1.fn(arg2, arg3, ...)
因此,只有当函数的结果可以作为第一个参数传递给下一个函数时,这种技术才有效。在DuckDB中,大多数函数的签名使这成为可能。
如果我们要重写上面的查询来使用链式调用,我们可以相当容易地做到这一点:
FROM (SELECT range(1,50,5).unnest() AS num)
SELECT
num,
CAST(num.sqrt().power(3).log2() AS INTEGER).factorial() AS val;
返回结果:
num|val |
---+------------------+
1| 0.0|
6| 3.877443751081734|
11|5.1891474279559455|
16| 6.0|
21| 6.588476134168141|
26| 7.050659577211638|
31| 7.431294465580312|
36| 7.754887502163468|
41| 8.036328006927125|
46| 8.28534293408552|
自定义转换函数
但是现在我们有点卡住了,因为我们不能链接CAST函数。我们可以像普通的那样编写CAST,然后调用factorial:
FROM (SELECT range(1,50,5).unnest() AS num)
SELECT
num,
CAST(num.sqrt().power(3).log2() AS INTEGER).factorial() AS val;
虽然解决了cast函数调用问题,但如果我们能把所有东西都锁起来,那还是很酷的。不幸的是,没有可以动态转换值的函数,这有点令人沮丧。但是我们可以做的是自己创建只用于转换为整数的函数:
CREATE OR REPLACE MACRO asInt(value) AS
CAST(value AS INTEGER);
现在可以链接所有查询中函数:
FROM (SELECT range(1,50,5).unnest() AS num)
SELECT
num,
num.sqrt().power(3).log2().asInt().factorial() AS val;
查询结果:
num|val |
---+-----+
1| 1|
6| 24|
11| 120|
16| 720|
21| 5040|
26| 5040|
31| 5040|
36|40320|
41|40320|
46|40320|
总结
是不是很酷,关于如何自定义函数(或宏),下次我们再分享。希望对你有用,一起学习。

1077

被折叠的 条评论
为什么被折叠?



