DeepSeek总结的DuckDB动态函数应用插件
来源:https://github.com/teaguesterling/duckdb_func_apply
DuckDB FuncApply 扩展
DuckDB 的动态函数应用 - 在运行时通过名称调用函数。
概述
FuncApply 扩展为 DuckDB 提供了动态函数调用能力,允许您:
- 使用
apply()通过名称调用任何标量函数或宏 - 使用
apply_with()动态传递参数 - 使用
apply_table()和apply_table_with()动态调用表函数 - 使用
function_exists()检查函数是否存在
这对于数据驱动的转换、动态 SQL 生成以及构建灵活的数据管道非常有用。
快速开始
-- 加载扩展LOADfunc_apply;-- 动态调用标量函数SELECTapply('upper','hello world');-- 结果: HELLO WORLDSELECTapply('substr','hello world',7,5);-- 结果: world-- 动态调用表函数SELECT*FROMapply_table('range',5);-- 返回: 0, 1, 2, 3, 4SELECT*FROMapply_table('generate_series',1,10,2);-- 返回: 1, 3, 5, 7, 9-- 在调用前检查函数是否存在SELECTfunction_exists('my_custom_func');-- 结果: true/false函数
apply(func_name, ...args)
使用提供的参数通过名称调用一个函数。
-- 字符串函数SELECTapply('upper','hello');-- HELLOSELECTapply('concat','a','b','c');-- abcSELECTapply('substr','hello',2,3);-- ell-- 数值函数SELECTapply('abs',-42);-- 42SELECTapply('round',3.14159,2);-- 3.14-- 列表函数(宏)SELECTapply('list_sum',[1,2,3,4]);-- 10SELECTapply('list_reverse',[1,2,3]);-- [3, 2, 1]-- 支持命名参数SELECTapply('substr','hello world',start:=7,length :=5);-- worldapply_with(func_name, args, kwargs)
使用作为列表提供的参数调用一个函数。
-- 基本用法SELECTapply_with('upper',args :=['hello']);-- 结果: HELLO-- 使用位置语法SELECTapply_with('concat',['a','b','c'],NULL);-- 结果: abc注意:DuckDB 列表必须是同质的(相同类型)。对于混合类型的参数,请直接使用apply()。
apply_table(func_name, ...args)
通过名称调用一个表函数,并将其结果作为表返回。
-- 基本范围SELECT*FROMapply_table('range',5);-- 返回: 0, 1, 2, 3, 4-- 带步长的生成序列SELECT*FROMapply_table('generate_series',1,10,2);-- 返回: 1, 3, 5, 7, 9-- 在连接中使用SELECTd.*,r.rangeasidxFROMmy_data dCROSSJOINapply_table('range',3)r;-- 在子查询中使用SELECT*FROMmy_tableWHEREidIN(SELECTrangeFROMapply_table('range',100));apply_table_with(func_name, args, kwargs)
使用作为列表提供的参数和可选的命名参数调用一个表函数。
-- 基本用法SELECT*FROMapply_table_with('range',args :=[5]);-- 返回: 0, 1, 2, 3, 4-- 使用命名参数SELECT*FROMapply_table_with('generate_series',args :=[1],kwargs :={stop:10,step:2});-- 返回: 1, 3, 5, 7, 9function_exists(name)
如果存在具有给定名称的函数,则返回 true。
SELECTfunction_exists('upper');-- trueSELECTfunction_exists('nonexistent');-- false-- 用于条件逻辑SELECTCASEWHENfunction_exists(func_name)THENapply(func_name,value)ELSE'N/A'ENDFROMmy_table;支持的函数类型
| 类型 | 是否支持 | 使用的函数 | 示例 |
|---|---|---|---|
| 标量函数 | 是 | apply,apply_with | upper,abs,substr |
| 宏 | 是 | apply,apply_with | list_sum,list_reverse |
| 表函数 | 是 | apply_table,apply_table_with | range,generate_series |
| 聚合函数 | 否 | 不适用 | sum,avg |
用例
数据驱动的转换
-- 在表中存储转换规则CREATETABLEtransforms(column_nameVARCHAR,func_nameVARCHAR);INSERTINTOtransformsVALUES('name','upper'),('email','lower'),('phone','trim');-- 动态应用转换SELECTapply(t.func_name,d.value)asresultFROMdatadJOINtransforms tONd.column=t.column_name;动态函数选择
-- 根据数据类型选择函数SELECTapply(CASEtypeof(value)WHEN'VARCHAR'THEN'upper'WHEN'INTEGER'THEN'abs'ELSE'to_string'END,value)FROMmy_table;执行前验证
-- 仅调用存在的函数SELECTfunc_name,CASEWHENfunction_exists(func_name)THENapply(func_name,'test')ELSE'Function not found'ENDasresultFROMfunction_list;动态表生成
-- 根据配置生成动态行数SELECT*FROMapply_table('range',row_count)WHERErow_count=(SELECTmax_rowsFROMconfig);-- 在交叉连接中使用表函数进行数据扩展SELECTd.*,idx.rangeaspositionFROMmy_data dCROSSJOINapply_table('range',d.repeat_count)idx;构建
先决条件
DuckDB 扩展使用 VCPKG 进行依赖管理:
gitclone https://github.com/Microsoft/vcpkg.git ./vcpkg/bootstrap-vcpkg.shexportVCPKG_TOOLCHAIN_PATH=`pwd`/vcpkg/scripts/buildsystems/vcpkg.cmake构建
make测试
maketest安装
从源码构建
构建后,扩展位于:
./build/release/extension/func_apply/func_apply.duckdb_extension在 DuckDB 中加载它:
LOAD'path/to/func_apply.duckdb_extension';未签名扩展
要加载未签名的扩展,请使用以下方式启动 DuckDB:
duckdb-unsigned或者在 Python 中:
con=duckdb.connect(':memory:',config={'allow_unsigned_extensions':'true'})文档
请参阅 docs/ 文件夹获取详细文档:
- API 参考 - 完整的函数参考
- 示例 - 使用示例和模式
- 内部实现 - 实现细节
许可证
MIT 许可证 - 详情请参阅 LICENSE 文件。
