利用DuckDB列表一句SQL输出乘法口诀表

先热身,用生成式列表输出几行不同长度的序列,从默认的标题列可知,生成式列表后台实际调用了list_apply函数。

sql 复制代码
D select [i for i in range(1,a+1)]from range(1,6)t(a);
┌─────────────────────────────────────────────────────┐
│ main.list_apply("range"(1, (a + 1)), (lambda i: i)) │
│                       int64[]                       │
├─────────────────────────────────────────────────────┤
│ [1]                                                 │
│ [1, 2]                                              │
│ [1, 2, 3]                                           │
│ [1, 2, 3, 4]                                        │
│ [1, 2, 3, 4, 5]                                     │
└─────────────────────────────────────────────────────┘

再把生成式的结果表达式变为字符串连接

sql 复制代码
D select [i::text||'*'||a::text||'='||(i*a)::text for i in range(1,a+1)]from range(1,6)t(a);
┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ main.list_apply("range"(1, (a + 1)), (lambda i: ((((CAST(i AS VARCHAR) || '*') || CAST(a AS VARCHAR)) || '=') || C...  │
│                                                      varchar[]                                                       │
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ ['1*1=1']                                                                                                            │
│ ['1*2=2', '2*2=4']                                                                                                   │
│ ['1*3=3', '2*3=6', '3*3=9']                                                                                          │
│ ['1*4=4', '2*4=8', '3*4=12', '4*4=16']                                                                               │
│ ['1*5=5', '2*5=10', '3*5=15', '4*5=20', '5*5=25']                                                                    │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

其中的强制转换可以省略,DuckDB会自动转换

sql 复制代码
D select [i||'*'||a||'='||(i*a) for i in range(1,a+1)]from range(1,6)t(a);
┌───────────────────────────────────────────────────────────────────────────────────────────┐
│ main.list_apply("range"(1, (a + 1)), (lambda i: ((((i || '*') || a) || '=') || (i * a)))) │
│                                         varchar[]                                         │
├───────────────────────────────────────────────────────────────────────────────────────────┤
│ ['1*1=1']                                                                                 │
│ ['1*2=2', '2*2=4']                                                                        │
│ ['1*3=3', '2*3=6', '3*3=9']                                                               │
│ ['1*4=4', '2*4=8', '3*4=12', '4*4=16']                                                    │
│ ['1*5=5', '2*5=10', '3*5=15', '4*5=20', '5*5=25']                                         │
└───────────────────────────────────────────────────────────────────────────────────────────┘

字符串列表形式的输出不美观,可以转换为纯字符串。listagg函数直接嵌套unnest函数的方法不支持。

sql 复制代码
D select listagg(unnest([i||'*'||a||'='||(i*a) for i in range(1,a+1)])) from range(1,6)t(a);
Binder Error:
UNNEST not supported here

LINE 1: select listagg(unnest([i||'*'||a||'='||(i*a) for i in range(1,a+1)])) from...
                       ^

但是可以单独对列表unnest,就把列表中多个值转成多行

sql 复制代码
D select unnest([i||'*'||a||'='||(i*a) for i in range(1,a+1)]) from range(1,6)t(a);
┌───────────────────────────────────────────────────────────────────────────────────────────────────┐
│ unnest(main.list_apply("range"(1, (a + 1)), (lambda i: ((((i || '*') || a) || '=') || (i * a))))) │
│                                              varchar                                              │
├───────────────────────────────────────────────────────────────────────────────────────────────────┤
│ 1*1=1                                                                                             │
│ 1*2=2                                                                                             │
│ 2*2=4                                                                                             │
│ 1*3=3                                                                                             │
│ 2*3=6                                                                                             │
│ 3*3=9                                                                                             │
│ 1*4=4                                                                                             │
│ 2*4=8                                                                                             │
│ 3*4=12                                                                                            │
│ 4*4=16                                                                                            │
│ 1*5=5                                                                                             │
│ 2*5=10                                                                                            │
│ 3*5=15                                                                                            │
│ 4*5=20                                                                                            │
│ 5*5=25                                                                                            │
├───────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                              15 rows                                              │
└───────────────────────────────────────────────────────────────────────────────────────────────────┘

还可以带上原来的列a

sql 复制代码
D select a,unnest([i||'*'||a||'='||(i*a) for i in range(1,a+1)]) from range(1,6)t(a);
┌───────┬───────────────────────────────────────────────────────────────────────────────────────────────────┐
│   a   │ unnest(main.list_apply("range"(1, (a + 1)), (lambda i: ((((i || '*') || a) || '=') || (i * a))))) │
│ int64 │                                              varchar                                              │
├───────┼───────────────────────────────────────────────────────────────────────────────────────────────────┤
│     1 │ 1*1=1                                                                                             │
│     2 │ 1*2=2                                                                                             │
│     2 │ 2*2=4                                                                                             │
│     3 │ 1*3=3                                                                                             │
│     3 │ 2*3=6                                                                                             │
│     3 │ 3*3=9                                                                                             │
│     4 │ 1*4=4                                                                                             │
│     4 │ 2*4=8                                                                                             │
│     4 │ 3*4=12                                                                                            │
│     4 │ 4*4=16                                                                                            │
│     5 │ 1*5=5                                                                                             │
│     5 │ 2*5=10                                                                                            │
│     5 │ 3*5=15                                                                                            │
│     5 │ 4*5=20                                                                                            │
│     5 │ 5*5=25                                                                                            │
├───────┴───────────────────────────────────────────────────────────────────────────────────────────────────┤
│ 15 rows                                                                                         2 columns │
└───────────────────────────────────────────────────────────────────────────────────────────────────────────┘

用listagg访问子查询就可以了,注意要针对列a排序

sql 复制代码
D select listagg(b,' ') from(select a,unnest([i||'*'||a||'='||(i*a) for i in range(1,a+1)])b from range(1,6)t(a))group by a;
┌───────────────────────────────────┐
│          listagg(b, ' ')          │
│              varchar              │
├───────────────────────────────────┤
│ 1*5=5 2*5=10 3*5=15 4*5=20 5*5=25 │
│ 1*1=1                             │
│ 1*4=4 2*4=8 3*4=12 4*4=16         │
│ 1*3=3 2*3=6 3*3=9                 │
│ 1*2=2 2*2=4                       │
└───────────────────────────────────┘
D select listagg(b,' ') from(select a,unnest([i||'*'||a||'='||(i*a) for i in range(1,a+1)])b from range(1,6)t(a))group by a order by a;
┌───────────────────────────────────┐
│          listagg(b, ' ')          │
│              varchar              │
├───────────────────────────────────┤
│ 1*1=1                             │
│ 1*2=2 2*2=4                       │
│ 1*3=3 2*3=6 3*3=9                 │
│ 1*4=4 2*4=8 3*4=12 4*4=16         │
│ 1*5=5 2*5=10 3*5=15 4*5=20 5*5=25 │
└───────────────────────────────────┘

上述输出随着数字变大,算式变长,没有对齐,可以用printf函数格式化,函数的格式符按照C语言的标准格式,-8表示8位宽左对齐,但注意格式符用单引号而不是双引号括起,双引号可以包括在单引号内原样输出。

sql 复制代码
D select listagg(printf('%-8s',b),' ') from(select a,unnest([i||'*'||a||'='||(i*a) for i in range(1,a+1)])b from range(1,6)t(a))group by a order by a;
┌──────────────────────────────────────────────┐
│       listagg(printf('%-8s', b), ' ')        │
│                   varchar                    │
├──────────────────────────────────────────────┤
│ 1*1=1                                        │
│ 1*2=2    2*2=4                               │
│ 1*3=3    2*3=6    3*3=9                      │
│ 1*4=4    2*4=8    3*4=12   4*4=16            │
│ 1*5=5    2*5=10   3*5=15   4*5=20   5*5=25   │
└──────────────────────────────────────────────┘

D select printf('Benchmark "%s" took %d seconds', 'CSV', 42);
┌─────────────────────────────────────────────────────┐
│ printf('Benchmark "%s" took %d seconds', 'CSV', 42) │
│                       varchar                       │
├─────────────────────────────────────────────────────┤
│ Benchmark "CSV" took 42 seconds                     │
└─────────────────────────────────────────────────────┘

以下是结合递归CTE用行间列表运算输出杨辉三角

sql 复制代码
D with recursive t as(select 1 lv, [1]y union all select lv+1,[case when i=1 or i=lv+1 then 1 else y[i-1]+y[i] end for i in range(1, lv+2)] from t where lv <5 )from t;
┌───────┬─────────────────┐
│  lv   │        y        │
│ int32 │     int32[]     │
├───────┼─────────────────┤
│     1 │ [1]             │
│     2 │ [1, 1]          │
│     3 │ [1, 2, 1]       │
│     4 │ [1, 3, 3, 1]    │
│     5 │ [1, 4, 6, 4, 1] │
└───────┴─────────────────┘
相关推荐
一只会写代码的猫1 小时前
深度解析 Java、C# 和 C++ 的内存管理机制:自动 vs 手动
java·jvm·算法
高山有多高1 小时前
堆应用一键通关: 堆排序 +TOPk问题的实战解析
c语言·数据结构·c++·算法
我命由我123452 小时前
Java 开发 - 简单消息队列实现、主题消息队列实现
java·开发语言·后端·算法·java-ee·消息队列·intellij-idea
2501_941237452 小时前
高性能计算通信库
开发语言·c++·算法
程序猿追2 小时前
Ascend C编程范式总结:与CUDA的异同对比
c语言·开发语言·算法
q***99632 小时前
SQL 中 COUNT 的用法详解
数据库·sql
wind_one12 小时前
9.基础--SQL--DML-插入
数据库·sql
float_六七2 小时前
SQL中=与IS的区别:关键用法解析
java·数据库·sql
rit84324992 小时前
配置Spring框架以连接SQL Server数据库
java·数据库·spring