1.将rusty_sheet插件用于其他版本
rusty_sheet新版插件只能用于DuckDB 1.4.1版,如果需要用于其他版本,需要对插件中的版本号字符串替换。可以用这个python脚本替换1.4.1版本中的字符串。
步骤如下
(1)在duckdb 1.4.1版中查到插件安装位置
用select install_path from duckdb_extensions() where install_path like '%rusty_sheet%';查询位置
(2)退出duckdb ,复制到别处
copy 位置 tmp
(3)用python脚本替换
(4)用-unsigned加载替换后的版本
duckdb132 -unsigned -cmd "load 'tmp\rusty_sheet.duckdb_extension' "
就可以在1.3.2版中使用新版的功能,比如访问网络文件。
from read_sheet('https://www.miit.gov.cn/cms_files/filemanager/1226211233/attach/20259/795cf87158b0441ea697899f4cf626c4.xlsx') limit 4;
2.让rusty_sheet支持可变参数。
比如我有一个表列出了xlsx文件的清单,需要从清单中选择某个文件,因为duckdb不支持表函数用其他查询的结果做参数,过去的方法是先生成一个SQL脚本,再查询。
但表函数利用duckdb的set variable功能,可以变相地实现可变参数。
sql
-- 假定有2个xlsx文件
D load excel;
D copy (select 1 a) to '1a.xlsx' (header 1);
D copy (select 2 b) to '2b.xlsx' (header 1);
-- 把它们的文件名和描述存在表中
D create table t as(select '1a.xlsx' f,'abc' d union select '2b.xlsx' ,'xyz');
-- 按描述查询文件名
D set variable n=(select f from t where d ='xyz');
D select getvariable('n');
┌──────────────────┐
│ getvariable('n') │
│ varchar │
├──────────────────┤
│ 2b.xlsx │
└──────────────────┘
-- 用变量n查询
D from read_sheet(getvariable('n'));
┌───────┐
│ b │
│ int64 │
├───────┤
│ 2 │
└───────┘
-- 如果返回超过1行
D set variable n=(select f from t);
Invalid Input Error:
More than one row returned by a subquery used as an expression - scalar subqueries can only return a single row.
Use "SET scalar_subquery_error_on_multiple_rows=false" to revert to previous behavior of returning a random row.
-- 用列表聚合
D set variable n=(select list(f) from t);
D select getvariable('n');
┌────────────────────┐
│ getvariable('n') │
│ varchar[] │
├────────────────────┤
│ [1a.xlsx, 2b.xlsx] │
└────────────────────┘
-- 用变量n查询2个文件
D from read_sheets(getvariable('n'));
┌───────┐
│ a │
│ int64 │
├───────┤
│ 1 │
│ 2 │
└───────┘
3.配合miniplot插件画统计图
(1)安装miniplot插件
sql
install miniplot from community;
load miniplot;
(2)查询xlsx文件
sql
D from read_sheets(['stocks_data.xlsx']) limit 2;
┌──────────┬─────────────────────┬────────┬────────┬────────┬────────┬──────────┬────────┬───────────┬────────────┬─────────────┬───────────┐
│ 股票代码 │ 时间 │ 开盘价 │ 最高价 │ 最低价 │ 收盘价 │ 前收盘价 │ 涨跌额 │ 涨跌幅(%) │ 成交量(股) │ 成交额(元) │ 换手率(%) │
│ varchar │ timestamp │ double │ double │ double │ double │ double │ double │ double │ int64 │ double │ double │
├──────────┼─────────────────────┼────────┼────────┼────────┼────────┼──────────┼────────┼───────────┼────────────┼─────────────┼───────────┤
│ STK00267 │ 2024-01-01 09:30:46 │ 98.45 │ 104.57 │ 92.74 │ 102.98 │ 98.83 │ 4.15 │ 4.2 │ 2182810 │ 224785773.8 │ 8.67 │
│ STK00417 │ 2024-01-01 09:30:47 │ 14.52 │ 15.37 │ 13.55 │ 14.8 │ 15.25 │ -0.45 │ -2.95 │ 5055707 │ 74824463.6 │ 7.98 │
└──────────┴─────────────────────┴────────┴────────┴────────┴────────┴──────────┴────────┴───────────┴────────────┴─────────────┴───────────┘
D select 股票代码,"涨跌幅(%)" from read_sheets(['stocks_data.xlsx']) order by "涨跌幅(%)" desc limit 5;
┌──────────┬───────────┐
│ 股票代码 │ 涨跌幅(%) │
│ varchar │ double │
├──────────┼───────────┤
│ STK01000 │ 14.65 │
│ STK00877 │ 14.45 │
│ STK00266 │ 13.57 │
│ STK00875 │ 13.34 │
│ STK00428 │ 12.8 │
└──────────┴───────────┘
D select bar_chart(list(股票代码),list("涨跌幅(%)"),'涨幅前五') from (select 股票代码,"涨跌幅(%)" from read_sheets(['stocks_data.xlsx']) order by "涨跌幅(%)" desc limit 5);
┌─────────────────────────────────────────────────────────────────────────────────────────┐
│ bar_chart(list("股票代码"), list("涨跌幅(%)"), '涨幅前五') │
│ varchar │
├─────────────────────────────────────────────────────────────────────────────────────────┤
│ C:\Users\lt\AppData\Local\Temp\duckdb_chart_b31dd0960259aef6eaf45c713731aa93_80624.html │
└─────────────────────────────────────────────────────────────────────────────────────────┘
就会在输出的结果给出的路径保存网页,同时在浏览器打开。注意%不是合法的列名字符,需要用双引号括起来。
4.利用xlsx文件保存lua源代码,用read_sheet读出后由lua插件执行
lua函数中难以输入多行代码,比如如下代码
--[[ 函数返回两个值的最大值 --]]
function max(num1, num2)
if (num1 > num2) then
result = num1;
else
result = num2;
end
return result;
end
-- 调用函数
print("两值比较最大值为 ",max(10,4))
print("两值比较最大值为 ",max(5,6))
可以用xlsx文件的单元格来存储带换行符的字符串。
因为lua函数需要一个返回值,就在末尾添加一行return 1,然后复制粘贴到一个单元格的输入框中保存。注意在最开头输入一个单引号表示单元格是字符串。然后就可以用如下SQL执行这段代码。
list模式可以显示换行。
sql
D .mode list
D from read_sheet('demo.xlsx',header=0);
A
--[[ 函数返回两个值的最大值 --]]
function max(num1, num2)
if (num1 > num2) then
result = num1;
else
result = num2;
end
return result;
end
-- 调用函数
print("两值比较最大值为 ",max(10,4))
print("两值比较最大值为 ",max(5,6))
return 1
.mode duckbox
D select lua(A) from read_sheet('demo.xlsx',header=0);
两值比较最大值为 10
两值比较最大值为 6
┌─────────┐
│ lua(A) │
│ varchar │
├─────────┤
│ 1 │
└─────────┘
更实用的代码如下,利用context变量传入参数,参数可以是字面值,也可以是表中的数据
sql
--[[ 函数返回两个值的最大值 --]]
function max(num1, num2)
if (num1 > num2) then
result = num1;
else
result = num2;
end
return result;
end
-- 调用函数
s=context
return max(s[1],s[2])
D select lua(A,[1,2]) from read_sheet('demo.xlsx',header=0);
┌───────────────────────────────┐
│ lua(A, main.list_value(1, 2)) │
│ json │
├───────────────────────────────┤
│ 2 │
└───────────────────────────────┘
D create table t as select 100 a,239 b;
D select lua(f.A,[t.a,b]) from read_sheet('demo.xlsx',header=0)f,t;
┌───────────────────────────────────┐
│ lua(f.A, main.list_value(t.a, b)) │
│ json │
├───────────────────────────────────┤
│ 239 │
└───────────────────────────────────┘
把xlsx文件作为保存自定义函数的库,在一定程度上可以弥补duckdb没有自定义函数的缺憾。