震惊,思源表格和数据库竟然可以用 SQL 查询

简单查询 更新啦!

原贴 [js] 简单查询,让数据从此不再难查,支持显示多字段多视图

0.0.2 带来了新功能,可以用用 SQL 查询数据库和表格!

另外,简单查询教程 1.0 发布啦!

安装

  1. 首先安装简单查询 js,到这里下载 https://gitee.com/wish163/mysoft/blob/main/%E6%80%9D%E6%BA%90/SQL%E7%AE%80%E5%8D%95%E6%9F%A5%E8%AF%A2.js?utm_source=ld246.com 放到思源 js 代码片段中即可。
  2. 然后安装简单查询 alasql 扩展,到这里下载 https://gitee.com/wish163/mysoft/blob/main/%E6%80%9D%E6%BA%90/SQL%E7%AE%80%E5%8D%95%E6%9F%A5%E8%AF%A2.alasql.js 放到思源 js 代码片段中即可。
  3. 编辑器输入 {{}} ,在弹出框中输入下面的示例代码就可以使用了。

用 SQL 查询数据库

比如有个名为 demo201 数据库

image.png

通过 SQL 查询如下

//!js
return query("select `序号` as `序号__w80_c:blue_0`, `内容` from ? limit 2", [fromAv('demo201'),item]);

结果:

image.png

这个 SQL 的含义是从数据库 demo201 中查询序号和内容字段,筛选前 2 条记录,并设置序号字段 80px 宽度,蓝色文字,排序到最前面。

`序号` as `序号__w80_c:blue_0` 中,为什么序号要加反撇号`,这是 SQL 语法,由于本功能使用了 alasql 扩展(注意是简单查询 js 的扩展,不是思源的插件),在 alasql 中不支持中文字段,中文字段需要加反撇号`。

w80 意思是该字段宽度为 80px,这是简单查询语法,称为字段标记符,可参考帖子 ,w 也可以写成 width, w 是简写,80 也可以写成 80px, 80em 等。

c:blue 意思是字段显示为蓝色,同样是简单查询语法,c 是 color 的意思,也可以写成 color,blue 也可以写成#00f。

最后的 0 是代表该字段排序编号,数字越小越靠前。

字段名和标记符之间用__隔开,标记符之间用_隔开。

注意,这里与简单查询语法不同的是

  1. 查询的表在 SQL 中用?号表示,然后用数组传入?号代表的真实数据,比如这里的 fromAv('xxx'),从数据库查询,这里的 xxx 可以是数据库的块 id,数据库 id,数据库名,系统会智能判断你输入的参数。
    类似的还有,fromTable('xxxx') 从表格查询,xxxx 是表格的块 id,fromSql('sql语句') 从 SQL 查询,即从 sqlite 中查询数据
  2. 原来简单查询的 item 参数现在变为了为 SQL 传递变量的数组,item 需要放到数组的最后面即可,比如这里的 [fromAv('demo201'), item] 这也好理解,原来是 item,现在需要有新成员加入了,如果不想新增参数的话,只有让房间隔开多个成员居住了,这里就是数组啦。

用 SQL 查询表格

基本查询

表格数据:

image.png

sql:

//!js
return query("select `aa` as `aa__w80_c:blue_0`, `bb` from ? where aa>55", [fromTable('20250110154352-pdr5v3t'),item]);

结果:

image.png

该 SQL 查询 aa 字段的值大于 55 的,并把 aa 字段设置为 80px 宽度,蓝色,排序到前面

汇总统计

sql:

//!js
return query("select sum(aa) as `aa列总和__w150` from ?", [fromTable('20250110154352-pdr5v3t'),item]);

结果:

image.png

该 SQL 汇总 aa 列,并重命名为“aa 列总和”,然后用 sum 函数汇总总和,并把列宽设为 150px。

更新表格

如果想汇总后更新原表格可以吗?

可以,比如,下面演示对上述表格 aa 列汇总总和后并插入一行新数据到原表格。

使用 SQL 统计:

//!js
try {
    return query("select * from ?", [fromTable('20250110154352-pdr5v3t'), item], '',
        async ({ rawData, updateTable, renderSuccess }) => {
            let sumAA = await query("select sum(aa) as total_aa from ? WHERE isNumeric(aa)", [fromTable('20250110154352-pdr5v3t'), null]);
            sumAA = sumAA[0]?.total_aa || 0;
            const hasTotal = (rawData[rawData.length - 1].aa + '').indexOf('合计') !== -1;
            const newIndex = hasTotal ? rawData.length - 1 : rawData.length;
            if (!rawData[newIndex]) rawData[newIndex] = {};
            rawData[newIndex].aa = '合计: ' + sumAA;
            rawData[newIndex].bb = '';
            rawData[newIndex].cc = '';
            updateTable('20250110154352-pdr5v3t', rawData);
            return renderSuccess('统计成功', item);
        }
    );
} catch (e) {
    console.error(e);
    return [];
}

这里加了 try{} catch(e) {} 但这不是必须的,当你的结果没有达到预期且没有报错时,可以尝试用 try 看看有没有什么报错信息。之所以要自己加 try 是因为思源拦截了错误信息。

这个 SQL 复杂的地方在于动态更新表格新行,且不影响旧数据,真正的统计就一行 sql 代码。

SQL 中的 isNumeric 这个函数并不是 alasql 自带的,而是自己定义的。扩展查询函数可以用 alasql.fn.xxx = ()=>{}扩展。也可以在简单查询用户自定义函数区定义函数,然后添加到 alaSqlFuncs 变量中即可。也可以通过 query(':regAlaSql:funcName', ()=>{})进行注册或在 alasql 扩展中等待 alasql.js 加载完成时注册。

注意,data 中新增行数据可能引起发嵌入块更新,从而再次新增行数据,引起死循环,所以这里推荐用 rawData 进行更新操作。

使用 js 统计:

//!js
return query("select * from ?", [fromTable('20250110154352-pdr5v3t'), item], '', ({ rawData, updateTable, renderSuccess }) => {
    const sumAA = rawData.reduce((total, item) => total + (parseFloat(item.aa)||0), 0);

    const hasTotal = (rawData[rawData.length-1].aa+'').indexOf('合计') !== -1;
    const newIndex = hasTotal ? rawData.length-1 : rawData.length;
    if(!rawData[newIndex]) rawData[newIndex] = {};
    rawData[newIndex].aa = '合计: '+sumAA;
    rawData[newIndex].bb='';
    rawData[newIndex].cc='';
    updateTable('20250110154352-pdr5v3t', rawData);
    return renderSuccess('统计成功', item);
});

这里用 js reduce 函数统计,其他同上。

结果:

image.png

你可能会吐槽,感觉并不简单。其实并不是的,统计很简单,无论 SQL 还是 js,一句代码就能统计了。如果没用这个查询,做这个统计就复杂了。

这里显得复杂的原因是因为要新增表格数据行,如果添加列会简单许多。

新增行要考虑哪些?

  1. 多次更新,合计不会不停的新加行
  2. 如果有些行数据不是数字怎么办?
  3. 第一次操作要新增,后面再次操作要更新,要实时计算最后一列的索引
  4. 统计时要去掉合计这个单元格等

所以,以上让代码变复杂了,而统计本身很简单,如果不是更新表本身,而是简单输出就没这些问题,比如上面的汇总总和,一句 SQL 就搞定了,这在以往实现起来很复杂的。

之所以选择这个复杂的例子,主要为了说明问题及提醒注意事项。

连表查询

还可以连表查询,不仅仅表格之间,数据库之间和 sqlite 之间都可以连查。

比如

image.png

查询代码:

//!js
return query("select a.id as id__w80_0, a.*,b.* from ? as a left join ? as b on a.id = b.id", [fromTable('20250111031121-dzax849'), fromTable('20250111063241-zit8y6r'), item]);

数据统计和汇总

用 SQL 对数据库统计更方便。

参考上面的表格统计和汇总,数据库也是类似的,不再赘述。

在模板中使用

这个查询也可以在模板中使用。

在文档模板中使用

与在嵌入块中查询类似,只要转换为模板嵌入代码即可,可参照上面的示例。

关于 SQL 代码和模板代码的转换可参考 思源能否在模板中发网络请求爬取数据呢? - wilsons 的回帖

在数据库模板中使用

利用数据库模板中的 img 标签,还可以在数据库模板中使用。

可参考 思源如何给日记模板添加天气 帖子中的第二点。

说明:虽然模板中可以使用,但使用较为复杂,如果想更新数据,需要配合数据库 api 进行操作。因此建议数据库统计在数据库外部进行比较合适。

当然,如果有兴趣研究的可提供一些思路,一是用思源 api,二是用 dom 操作,如果同一个文档的话,三是使用 getAttributeView api 或直接读取 json 文件,然后直接对 json 对象进行行或列操作,完成后再写入文件,这样反而简单许多。

自定义用法

如果你想使用 alasql 更多用法,封装的 query 查询不能满足你的需要。

也可以直接用 alasql 查询,只要把查询结果传给 query 函数的第一个参数即可。

比如,

//!js
return (async ()=>{
    return query(alasql("select `序号` as `序号__w80_c:blue_0`, `内容` from ? limit 2", [await fromAv('demo201', true)]), item);
})();

这里 alasql 中也可以使用字段标记符。

注意,这里加了立即函数,这是因为思源嵌入块函数体中不能直接用异步函数,必须再封装一层,因为这里 fromAv 要读取数据,因此用了 await 且加了第一个参数 true,表示真正读取数据。而用 query 查询时,在思源嵌入块函数体内时并没有真正的查询数据,只有进入 query 函数才真正的查询,这是为了在嵌入块函数体中,让 query 函数不用再封装一层立即函数。

常见问题

偶尔可能出现 query 未定义情况,虽然很少出现。这是因为,如果刷新页面时,刚好当前文档中有嵌入块 js,思源代码片段并不能保证一定在嵌入块执行前加载完毕,所以才出现这个错误。

不过,通常影响不大,如果有问题,关闭文档重新打开就好了,或者按 f5 刷新下。

正确的方式应该是在嵌入块查询 js 中等待 query 加载完毕后执行或者设置一定的延迟,不过,由于这个问题极少出现,且影响不大,一般不用特别去处理,如果偶尔出现错误,知道原因及如何处理就好了。

  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    24774 引用 • 101880 回帖
  • 代码片段

    代码片段分为 CSS 与 JS 两种代码,添加在 [设置 - 外观 - 代码片段] 中,这些代码会在思源笔记加载时自动执行,用于改善笔记的样式或功能。

    用户在该标签下分享代码片段时需在帖子标题前添加 [css] [js] 用于区分代码片段类型。

    133 引用 • 884 回帖
1 操作
wilsons 在 2025-01-27 12:50:20 更新了该帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...