求助将数据库中的内容渲染为表格

求助一个将数据库内容渲染为表格的方法

起因是看到了这一篇帖子利用 数据库 和 Chart(图表) 做小朋友身高管理 - 链滴,就想着是否有方法可以将数据库中的内容做成表格。


比如有这样一个数据库,每个主键有横坐标(A-B)和纵坐标(1-9)两个字段。

image.png

是否可以根据每个主键的横坐标和纵坐标两个字段,通过图表渲染成类似下面这种表格呢?感觉做一个物品管理蛮有意思的,数据库中添加其他字段描述物品信息,根据表格找到物品存放位置或者坐标(比如中药柜)

image.png


大家有什么好的方法吗(代码这方面我是真没时间学,之前也没接触过 😂)

  • 思源笔记

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

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

    24798 引用 • 101980 回帖 • 1 关注
  • Q&A

    提问之前请先看《提问的智慧》,好的问题比好的答案更有价值。

    9404 引用 • 42849 回帖 • 110 关注

相关帖子

被采纳的回答
  • wilsons 3 1 赞同

    那个帖子是根据 [js] 图表如何和表格联动 - wilsons 的回帖 这个改造的,这种方式需要自己手动解析数据库 json 数据,较为麻烦。

    建议使用简单查询,实现起来更方便,可参考 震惊,思源表格和数据库竟然可以用 SQL 查询

    然后,分别新建一个数据和表格,并复制数据库块 id 和表格块 id,然后在当前文档输入 {{}} 在弹出的对话框中,输入以下代码,并把刚才复制的 id 填入到下面的相应参数中即可

    //!js
    
    // 数据库块id
    const avBlockId = '20250311063435-9066xpv';
    
    // 表格块id
    const tableBlockId = '20250311063452-p03kxva';
    
    // 数据库变更后自动更新延迟,单位是毫秒,默认是1秒,0则不自动更新
    // 注意:更新该参数后需要刷新页面才能生效
    const autoFreshDelay = 1000;
    
    // 监听数据库变化
    observeAvChange();
    
    return query(
        "select * from ?",
        [fromAv(avBlockId), item],
        '',
        ({ rawData, updateTable, renderSuccess }) => {
            let tableData = transformData(rawData);
            tableData = toMarkdownTable(tableData);
            updateTable(tableBlockId, tableData);
            return renderSuccess('更新完成', item);
        }
    );
    
    function toMarkdownTable(data) {
        // 提取所有列名(包括空列 "")
        const columns = Array.from(
            data.reduce((set, row) => {
                Object.keys(row).forEach(key => set.add(key));
                return set;
            }, new Set())
        ).sort((a, b) => (a === "" ? -1 : a.localeCompare(b))); // 确保空列 "" 在最前面
    
        // 构造表头行
        const headerRow = `| ${columns.map(col => (col === "" ? "" : col)).join(" | ")} |`;
    
        // 构造分隔符行
        const separatorRow = `| ${columns.map(() => "---").join(" | ")} |`;
    
        // 构造数据行
        const dataRows = data.map(row => {
            return `| ${columns.map(col => row[col] || "").join(" | ")} |`;
        });
    
        // 拼接所有部分
        return [headerRow, separatorRow, ...dataRows].join("\n");
    }
    
    function transformData(input) {
        // 创建一个 Map 来按横坐标分组
        const groupedData = new Map();
    
        // 遍历输入数组,按横坐标分组
        input.forEach(item => {
            const { 主键, 横坐标, 纵坐标 } = item;
    
            // 如果横坐标不存在于 Map 中,则初始化
            if (!groupedData.has(横坐标)) {
                groupedData.set(横坐标, { "": 横坐标 });
            }
    
            // 将纵坐标和主键添加到对应的横坐标分组中
            groupedData.get(横坐标)[纵坐标] = 主键;
        });
    
        // 将 Map 转换为数组并返回
        return Array.from(groupedData.values());
    }
    
    function observeAvChange() {
        // 监听av变化,当数据库块被修改时,重新获取数据
        if(autoFreshDelay > 0 && !window['__table_observe__' + avBlockId]) {
            window['__table_observe__' + avBlockId] = observeDOMChanges(document.querySelector('div[data-node-id="'+avBlockId+'"]'), ()=>{
                setTimeout(() => {
                    item.querySelector('.protyle-action__reload').click();
                }, 100);
            }, autoFreshDelay, {attributes: false});
        }
    }
    
    // 监听dom变化
    function observeDOMChanges(targetNode, callback, debounceTime = 1000, options = {}) {
        // 默认配置
        const defaultOptions = {
          attributes: true,
          childList: true,
          subtree: true,
        };
    
        // 合并默认配置与传入的配置
        const config = Object.assign({}, defaultOptions, options);
    
        // 创建一个观察器实例
        const observer = new MutationObserver((mutationsList) => {
            // 使用防抖函数确保单位时间内最多只调用一次回调
            if(window['__table_observeTimer__' + avBlockId]) {
                clearTimeout(window['__table_observeTimer__' + avBlockId]);
            }
            window['__table_observeTimer__' + avBlockId] = setTimeout(() => {
                // 处理变化
                callback(mutationsList);
            }, debounceTime);
        });
    
        // 开始观察目标节点
        observer.observe(targetNode, config);
    
        // 返回一个函数,以便在不需要时能够停止观察
        return () => {
          observer.disconnect();
        };
    }
    

    r118.gif

欢迎来到这里!

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

注册 关于
请输入回帖内容 ...
  • 这个插件可能可以,但我完全不知道怎么用:

    image.png

    1 回复
  • auric

    我也看到这个插件,但是我也不知道咋用 😭 ,还是我太笨了。

  • wilsons 3 1 赞同

    那个帖子是根据 [js] 图表如何和表格联动 - wilsons 的回帖 这个改造的,这种方式需要自己手动解析数据库 json 数据,较为麻烦。

    建议使用简单查询,实现起来更方便,可参考 震惊,思源表格和数据库竟然可以用 SQL 查询

    然后,分别新建一个数据和表格,并复制数据库块 id 和表格块 id,然后在当前文档输入 {{}} 在弹出的对话框中,输入以下代码,并把刚才复制的 id 填入到下面的相应参数中即可

    //!js
    
    // 数据库块id
    const avBlockId = '20250311063435-9066xpv';
    
    // 表格块id
    const tableBlockId = '20250311063452-p03kxva';
    
    // 数据库变更后自动更新延迟,单位是毫秒,默认是1秒,0则不自动更新
    // 注意:更新该参数后需要刷新页面才能生效
    const autoFreshDelay = 1000;
    
    // 监听数据库变化
    observeAvChange();
    
    return query(
        "select * from ?",
        [fromAv(avBlockId), item],
        '',
        ({ rawData, updateTable, renderSuccess }) => {
            let tableData = transformData(rawData);
            tableData = toMarkdownTable(tableData);
            updateTable(tableBlockId, tableData);
            return renderSuccess('更新完成', item);
        }
    );
    
    function toMarkdownTable(data) {
        // 提取所有列名(包括空列 "")
        const columns = Array.from(
            data.reduce((set, row) => {
                Object.keys(row).forEach(key => set.add(key));
                return set;
            }, new Set())
        ).sort((a, b) => (a === "" ? -1 : a.localeCompare(b))); // 确保空列 "" 在最前面
    
        // 构造表头行
        const headerRow = `| ${columns.map(col => (col === "" ? "" : col)).join(" | ")} |`;
    
        // 构造分隔符行
        const separatorRow = `| ${columns.map(() => "---").join(" | ")} |`;
    
        // 构造数据行
        const dataRows = data.map(row => {
            return `| ${columns.map(col => row[col] || "").join(" | ")} |`;
        });
    
        // 拼接所有部分
        return [headerRow, separatorRow, ...dataRows].join("\n");
    }
    
    function transformData(input) {
        // 创建一个 Map 来按横坐标分组
        const groupedData = new Map();
    
        // 遍历输入数组,按横坐标分组
        input.forEach(item => {
            const { 主键, 横坐标, 纵坐标 } = item;
    
            // 如果横坐标不存在于 Map 中,则初始化
            if (!groupedData.has(横坐标)) {
                groupedData.set(横坐标, { "": 横坐标 });
            }
    
            // 将纵坐标和主键添加到对应的横坐标分组中
            groupedData.get(横坐标)[纵坐标] = 主键;
        });
    
        // 将 Map 转换为数组并返回
        return Array.from(groupedData.values());
    }
    
    function observeAvChange() {
        // 监听av变化,当数据库块被修改时,重新获取数据
        if(autoFreshDelay > 0 && !window['__table_observe__' + avBlockId]) {
            window['__table_observe__' + avBlockId] = observeDOMChanges(document.querySelector('div[data-node-id="'+avBlockId+'"]'), ()=>{
                setTimeout(() => {
                    item.querySelector('.protyle-action__reload').click();
                }, 100);
            }, autoFreshDelay, {attributes: false});
        }
    }
    
    // 监听dom变化
    function observeDOMChanges(targetNode, callback, debounceTime = 1000, options = {}) {
        // 默认配置
        const defaultOptions = {
          attributes: true,
          childList: true,
          subtree: true,
        };
    
        // 合并默认配置与传入的配置
        const config = Object.assign({}, defaultOptions, options);
    
        // 创建一个观察器实例
        const observer = new MutationObserver((mutationsList) => {
            // 使用防抖函数确保单位时间内最多只调用一次回调
            if(window['__table_observeTimer__' + avBlockId]) {
                clearTimeout(window['__table_observeTimer__' + avBlockId]);
            }
            window['__table_observeTimer__' + avBlockId] = setTimeout(() => {
                // 处理变化
                callback(mutationsList);
            }, debounceTime);
        });
    
        // 开始观察目标节点
        observer.observe(targetNode, config);
    
        // 返回一个函数,以便在不需要时能够停止观察
        return () => {
          observer.disconnect();
        };
    }
    

    r118.gif

    3 回复
    2 操作
    wilsons 在 2025-03-11 09:50:26 更新了该回帖
    wilsons 在 2025-03-11 09:46:42 更新了该回帖
  • auric

    感谢 w 佬,之前的两篇简单查询的帖子我也学习过,但是实际应用的时候还是丈二和尚摸不着头脑,这方面我基本没有基础 😂 。非常感谢 w 佬花时间帮助我们!

  • auric

    W 佬,我用这个查询的时候出现了一点问题。我想要一个 9×9 的表格,渲染出来的结果主键移位了,数据库中的数据是这样的,但是表格中 A3 A4 的主键数据跳到了 I8 I9,往后继续输入主键内容也是错位的。

    image.png

    image.png

    1 回复
  • auric

    w 佬,有点奇怪,我换到其他的数据库和表格后就没有出现这个错误求助将数据库中的内容渲染为表格 - auric 的回帖 - 链滴,不知道怎么回事。

  • 你把这个有问题的文件导出来看看,我刚才也在尝试复现,还没尝试出来。

    2 回复
  • auric

    测试.sy.zip 这是我测试好像有问题的文件,根据字段的插入块相应位置的代码。然后我用另外的两个数据库和表格,能够正确渲染到表格,但是添加之后就不能显示在正常的表格对应位置。

    1 回复
  • auric

    不知道是不是我代码改的不对,这是错误的录屏:

    20250311173219.gif

    另外可以正确导出表格的数据库,新增数据后,新增的数据直接出现在表格的第一个格里,也没有出现在相应的格子 😂

  • 这个问题,是思源笔记渲染结果和 api 解析不一致导致的。

    已向官方提交了 issue Issue #14345 · siyuan-note/siyuan

    暂时解决不了,你可以关注下这个 issue,等待官方回复后再看怎么解决。

    2 回复
  • auric

    ok,谢谢 w 佬 ❤️

  • auric

    哈喽,w 佬,我看了 GitHub 上的 issue,这个问题好解决么,不好解决的话,我今天发现直接新建数据库,不要改动排序,输入的内容不会有太大问题 😂 ,就是用的时候需要小心 😂

    1 回复
  • 是的,就是渲染数据和存储数据不一致导致的。这个要改成读渲染数据。这两种数据格式完全不一样,由于是底层,上层依赖较多,修改后影响较大,要做中间兼容层,改动较麻烦。

    2 回复
  • auric

    谢谢 w 佬 🙏

  • auric

    w 佬,现在的这个方法,只要渲染好了,修改条目的字段内容时不会有影响,如果在没有内容的条目字段里输入,就会渲染到表格的第一个空格内 😂 ,不过这个方法对我目前的需求来讲算不上很难接受,再次谢谢 w 佬提供的这些 ❤️

请输入回帖内容 ...

推荐标签 标签

  • Mac

    Mac 是苹果公司自 1984 年起以“Macintosh”开始开发的个人消费型计算机,如:iMac、Mac mini、Macbook Air、Macbook Pro、Macbook、Mac Pro 等计算机。

    167 引用 • 595 回帖 • 1 关注
  • 数据库

    据说 99% 的性能瓶颈都在数据库。

    345 引用 • 742 回帖 • 1 关注
  • frp

    frp 是一个可用于内网穿透的高性能的反向代理应用,支持 TCP、UDP、 HTTP 和 HTTPS 协议。

    20 引用 • 7 回帖
  • Access
    1 引用 • 3 回帖 • 6 关注
  • React

    React 是 Facebook 开源的一个用于构建 UI 的 JavaScript 库。

    192 引用 • 291 回帖 • 383 关注
  • 又拍云

    又拍云是国内领先的 CDN 服务提供商,国家工信部认证通过的“可信云”,乌云众测平台认证的“安全云”,为移动时代的创业者提供新一代的 CDN 加速服务。

    20 引用 • 37 回帖 • 570 关注
  • iOS

    iOS 是由苹果公司开发的移动操作系统,最早于 2007 年 1 月 9 日的 Macworld 大会上公布这个系统,最初是设计给 iPhone 使用的,后来陆续套用到 iPod touch、iPad 以及 Apple TV 等产品上。iOS 与苹果的 Mac OS X 操作系统一样,属于类 Unix 的商业操作系统。

    87 引用 • 139 回帖
  • 外包

    有空闲时间是接外包好呢还是学习好呢?

    26 引用 • 233 回帖
  • SpaceVim

    SpaceVim 是一个社区驱动的模块化 vim/neovim 配置集合,以模块的方式组织管理插件以
    及相关配置,为不同的语言开发量身定制了相关的开发模块,该模块提供代码自动补全,
    语法检查、格式化、调试、REPL 等特性。用户仅需载入相关语言的模块即可得到一个开箱
    即用的 Vim-IDE。

    3 引用 • 31 回帖 • 116 关注
  • ActiveMQ

    ActiveMQ 是 Apache 旗下的一款开源消息总线系统,它完整实现了 JMS 规范,是一个企业级的消息中间件。

    19 引用 • 13 回帖 • 677 关注
  • Telegram

    Telegram 是一个非盈利性、基于云端的即时消息服务。它提供了支持各大操作系统平台的开源的客户端,也提供了很多强大的 APIs 给开发者创建自己的客户端和机器人。

    5 引用 • 35 回帖 • 2 关注
  • 支付宝

    支付宝是全球领先的独立第三方支付平台,致力于为广大用户提供安全快速的电子支付/网上支付/安全支付/手机支付体验,及转账收款/水电煤缴费/信用卡还款/AA 收款等生活服务应用。

    29 引用 • 347 回帖
  • Notion

    Notion - The all-in-one workspace for your notes, tasks, wikis, and databases.

    10 引用 • 76 回帖
  • NetBeans

    NetBeans 是一个始于 1997 年的 Xelfi 计划,本身是捷克布拉格查理大学的数学及物理学院的学生计划。此计划延伸而成立了一家公司进而发展这个商用版本的 NetBeans IDE,直到 1999 年 Sun 买下此公司。Sun 于次年(2000 年)六月将 NetBeans IDE 开源,直到现在 NetBeans 的社群依然持续增长。

    78 引用 • 102 回帖 • 702 关注
  • Elasticsearch

    Elasticsearch 是一个基于 Lucene 的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于 RESTful 接口。Elasticsearch 是用 Java 开发的,并作为 Apache 许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。

    117 引用 • 99 回帖 • 205 关注
  • Kotlin

    Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言,由 JetBrains 设计开发并开源。Kotlin 可以编译成 Java 字节码,也可以编译成 JavaScript,方便在没有 JVM 的设备上运行。在 Google I/O 2017 中,Google 宣布 Kotlin 成为 Android 官方开发语言。

    19 引用 • 33 回帖 • 76 关注
  • Flutter

    Flutter 是谷歌的移动 UI 框架,可以快速在 iOS 和 Android 上构建高质量的原生用户界面。 Flutter 可以与现有的代码一起工作,它正在被越来越多的开发者和组织使用,并且 Flutter 是完全免费、开源的。

    39 引用 • 92 回帖
  • SMTP

    SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。SMTP 协议属于 TCP/IP 协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。

    4 引用 • 18 回帖 • 637 关注
  • OAuth

    OAuth 协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是 oAuth 的授权不会使第三方触及到用户的帐号信息(如用户名与密码),即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此 oAuth 是安全的。oAuth 是 Open Authorization 的简写。

    36 引用 • 103 回帖 • 28 关注
  • Logseq

    Logseq 是一个隐私优先、开源的知识库工具。

    Logseq is a joyful, open-source outliner that works on top of local plain-text Markdown and Org-mode files. Use it to write, organize and share your thoughts, keep your to-do list, and build your own digital garden.

    7 引用 • 69 回帖 • 1 关注
  • ZeroNet

    ZeroNet 是一个基于比特币加密技术和 BT 网络技术的去中心化的、开放开源的网络和交流系统。

    1 引用 • 21 回帖 • 638 关注
  • 架构

    我们平时所说的“架构”主要是指软件架构,这是有关软件整体结构与组件的抽象描述,用于指导软件系统各个方面的设计。另外还有“业务架构”、“网络架构”、“硬件架构”等细分领域。

    143 引用 • 442 回帖
  • Webswing

    Webswing 是一个能将任何 Swing 应用通过纯 HTML5 运行在浏览器中的 Web 服务器,详细介绍请看 将 Java Swing 应用变成 Web 应用

    1 引用 • 15 回帖 • 638 关注
  • Electron

    Electron 基于 Chromium 和 Node.js,让你可以使用 HTML、CSS 和 JavaScript 构建应用。它是一个由 GitHub 及众多贡献者组成的活跃社区共同维护的开源项目,兼容 Mac、Windows 和 Linux,它构建的应用可在这三个操作系统上面运行。

    15 引用 • 136 回帖 • 8 关注
  • Kafka

    Kafka 是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据。 这种动作(网页浏览,搜索和其他用户的行动)是现代系统中许多功能的基础。 这些数据通常是由于吞吐量的要求而通过处理日志和日志聚合来解决。

    36 引用 • 35 回帖
  • SOHO

    为成为自由职业者在家办公而努力吧!

    7 引用 • 55 回帖 • 5 关注
  • 微软

    微软是一家美国跨国科技公司,也是世界 PC 软件开发的先导,由比尔·盖茨与保罗·艾伦创办于 1975 年,公司总部设立在华盛顿州的雷德蒙德(Redmond,邻近西雅图)。以研发、制造、授权和提供广泛的电脑软件服务业务为主。

    8 引用 • 44 回帖