SQL 嵌入查询的致命缺陷:递归死循环与无法实现“原子级”内容聚合

问题图片

PixPin_2025-12-14_09-05-55


1. 应用场景与核心需求 (Use Case)

场景描述:

我正在构建一个基于思源笔记的深度知识管理系统(System)。我的核心工作流是:在长文档中对关键的“洞见”或“结论”进行高亮标记(通常使用 Alt+X 给整个块/列表项上色),然后希望通过 嵌入式 SQL 查询 (Embed SQL Query),在文档顶部或汇总页自动聚合这些高亮内容,形成一个 Dashboard。

核心需求:

  1. 聚合: 自动筛选出所有打了特定颜色属性(ial)的块。
  2. 原子化展示: 我只希望看到被我标记的那一行内容。即便这个块是一个列表项(List Item),且下方包含大量子块(Sub-nodes),我也希望在查询结果中只渲染父级内容,而不带出下方所有子节点。
  3. 同文档查询: 我经常需要在当前文档内部进行查询汇总(例如:在文档开头汇总本文档的所有高亮重点)。

2. 遇到的问题与情况还原 (Issue Reproduction)

在尝试通过 SQL 实现上述需求时,遇到了两个无法解决的底层逻辑冲突:

问题 A:镜像死循环 (Infinite Recursive Rendering)

当我在一篇文档内使用 SQL 查询“本文档内标绿的块”时,由于 嵌入查询块本身(或其父级容器)不可避免地会被卷入查询范围(例如查询块在标绿的列表下,或查询条件宽泛),导致渲染引擎陷入死循环。

  • 现象: 查询结果中渲染了查询块本身,而那个渲染出来的查询块又再次执行查询……形成了“无限套娃”。

  • 截图证据:

    [此处插入那张“查询结果里套着查询结果,无限重复”的截图]

问题 B:容器强制渲染子节点 (Forced Context Rendering)

当我对一个列表项(type='i')使用 Alt+X 上色后,SQL 查询该块。

  • 现象: 思源的渲染引擎强制将该列表项下方的所有子块(子列表、引用、图片等)全部渲染出来。哪怕我只想看第一行的结论,它也会把下方几千字的论证全部带出来。这导致聚合页面充满了无关的“噪音”。

  • 截图证据:

    [此处插入那张“查询标题/列表项,结果下方未标绿的内容全被带出来”的截图]


3. 尝试过的方案 (Attempted Solutions)

为了解决上述问题,我尝试了极其复杂的 SQL 过滤逻辑,但均以失败告终:

  1. 尝试阻断死循环:

    • 代码:AND content NOT LIKE '%SELECT%'AND markdown NOT LIKE...
    • 结果:失败。 似乎在 SQL 过滤生效前,渲染管道就已经捕获了该块,或者在某些层级嵌套下无法排除自身。
  2. 尝试阻断子节点渲染:

    • 代码:AND type != 'i' (排除列表项)
    • 结果:失败。 因为我用的是 Alt+X 给列表项上色,排除列表项后,我的数据就全丢了。
    • 尝试:使用子查询 SELECT * FROM blocks WHERE parent_id IN (标绿的列表项)
    • 结果:失败。 渲染逻辑依然混乱,且无法准确还原上下文。
  3. 尝试只查原子类型:

    • 代码:AND type IN ('h', 'p')
    • 结果:失败。 只要标题或段落位于一个被渲染的容器内,容器依然会接管渲染行为。

4. 逻辑上预期的样子 (Expected Behavior)

我认为一个成熟的双链笔记数据库,在处理 Query 时应具备以下能力:

  1. 自动防自爆机制: 嵌入式查询块 (Embed Query Block) 应该默认具备 "Self-Exclusion" (自我排除) 的逻辑。无论 SQL 怎么写,都不应该允许查询块渲染它自己,这是防止 UI 崩溃的底线。

  2. “内容模式”渲染 (Content-Only Rendering):

    • 目前的渲染逻辑是:Query Block -> Render Block(ID)。如果 ID 是列表项,则渲染整棵树。
    • 诉求: 需要一种机制(也许是 SQL 的某个参数,或者 UI 选项),允许用户 “只渲染块内容 (content),忽略子节点”
    • 就像:SELECT content_only(id) ...。我只想要那个“箱子”上的标签,不想要“箱子”里的货。

5. 观点与诉求 (Conclusion)

目前的 SQL 查询功能在 “内容聚合” 这一高频场景下显得非常尴尬(Chicken Ribs):

  • 它能查到数据,但 渲染方式 极其不可控。
  • 对于追求结构化笔记的用户(重度大纲/列表使用者),一旦使用了 Alt+X 排版,SQL 查询基本上就不可用了,因为无法剥离上下文。

强烈建议官方:

  1. 修复同文档查询的死循环 Bug,在底层切断递归。
  2. 引入“原子化渲染”选项,允许在嵌入查询中只展示块本身的文本,而不级联展示其子块。

这将极大地释放思源笔记作为“个人知识数据库”的潜力。希望能得到开发团队的重视。


附上几个错误代码:

这些代码都有这些问题,我尝试了 10 几个代码都无法解决这个问题:

SELECT * FROM blocks 
WHERE root_id = '20251210211043-chdub1j' 

-- 【防死循环绝对领域】
-- 排除代码块(c)和HTML块(m)。
-- 只要你的 SQL 写在代码块里,这一行能 100% 物理熔断死循环。
AND type NOT IN ('c', 'm')

AND (
    -- 【情况 A:你直接给文字/标题上了色】
    (
        type IN ('h', 'p') -- 只查标题和段落
        AND (
            ial LIKE '%background-color: var(--b3-card-info-background)%'
            OR ial LIKE '%background-color: var(--b3-card-success-background)%'
            OR ial LIKE '%background-color: var(--b3-card-warning-background)%'
            OR ial LIKE '%background-color: var(--b3-card-error-background)%'
        )
    )
  
    OR
  
    -- 【情况 B:你给圆点(列表项)上了色 (Alt+X 的习惯)】
    -- 这里的逻辑是:查那些“爸爸是绿色列表项”的段落。
    -- 这样查出来的是“段落(p)”,而不是“容器(i)”,所以绝对不会带出子节点!
    (
        type = 'p' -- 我只显示文字
        AND parent_id IN (
            SELECT id FROM blocks 
            WHERE root_id = '20251211235937-ewjmhk7' -- 子查询也要限定文档
            AND type = 'i' -- 找到所有绿色的列表项容器
            AND (
                ial LIKE '%background-color: var(--b3-card-info-background)%'
                OR ial LIKE '%background-color: var(--b3-card-success-background)%'
                OR ial LIKE '%background-color: var(--b3-card-warning-background)%'
                OR ial LIKE '%background-color: var(--b3-card-error-background)%'
            )
        )
    )
)
ORDER BY sort ASC
LIMIT 999
SELECT * FROM blocks 
WHERE root_id = '20251210211043-chdub1j' 
AND (
    ial LIKE '%background-color: var(--b3-card-info-background)%'
    OR ial LIKE '%background-color: var(--b3-card-success-background)%'
    OR ial LIKE '%background-color: var(--b3-card-warning-background)%'
    OR ial LIKE '%background-color: var(--b3-card-error-background)%'
)
select * from blocks where path like '%/20250402102311-bhl0ohe%' and (markdown like '%background-color: var(--b3-card-success-background); color: var(--b3-card-success-color);%' or ial like '%background-color: var(--b3-card-success-background); color: var(--b3-card-success-color);%');

以下是测试内容:

PixPin_2025-12-14_09-10-58

信息

成功

无格式信息

警告

错误
  • 这是列表块,这句话不想被查询。

    • 这句话标绿,只想要这句话被查询。这句话想被查询。

以下是测试错误截图

PixPin_2025-12-14_09-19-22

其他吐槽:

Ⅰ. 承认失败:查询功能的“伪神性”

我们在前几轮对话中犯了一个错误:试图用 SQL(逻辑语言) 去强行对抗 思源的渲染机制(物理规则)

事实证明,思源的 Embed Query (嵌入式查询) 存在致命缺陷:

  1. 渲染粒度过粗: 它不懂什么叫“只取一行字”。它只懂“取一个块”。而块往往连带着容器(列表、引述),这导致了你遇到的“株连九族”问题。
  2. 自我指涉的黑洞: 它无法优雅地处理“我在查询我自己”的逻辑,导致了死循环。
  3. 视觉噪音: 查出来的东西带着原有的格式、圆点、父级背景,这对于追求极致清晰的人 来说,是一坨视觉垃圾。

结论: 如果你的目的是 “动态聚合 Dashboard” (比如把所有标绿的重点自动汇聚成一张表),思源是不及格的。在这个功能上,它连 Logseq 的脚后跟都摸不到。


示例文档如下:↓↓↓↓↓↓↓↓↓

通用测试.sy.zip

  • 思源笔记

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

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

    28446 引用 • 119783 回帖
2 操作
1ssss 在 2025-12-14 13:31:46 更新了该帖
1ssss 在 2025-12-14 13:31:17 更新了该帖

相关帖子

欢迎来到这里!

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

注册 关于
请输入回帖内容 ...
  • ACai 1 2 评论

    可以尝试用 js,嵌入块是支持的。

    另外 query view 插件也可以打配合(强力推荐)。

    尝试ing
    1ssss
    用 js 成了 感动坏了 我最早就下载了 query view,但是不会用。后来我把 query view 的说明喂 AI,搞了好几波后居然成了 🤣
    1ssss
  • 这个方式有问题,不要用颜色判断,可以试试块属性,图右下角的我把备注重写了,然后内容记录大段记录下来,可以做查询。然后再说一句,你在做的是高端玩家的事,思源表格本质是在原有数据库结构上的功能堆叠。

    mmexport1765676584928.jpg

  • PearlLin 1 评论
    1. 原子化展示: 我只希望看到被我标记的那一行内容。即便这个块是一个列表项(List Item),且下方包含大量子块(Sub-nodes),我也希望在查询结果中只渲染父级内容,而不带出下方所有子节点。

    太长不看。单这一条论,你用块类型筛选,用 type = p 应该就可以做到。具体原理请看思源列表的嵌套结构。

    ps,如果你仅仅是需求当前文档的行内元素聚合的话,我记得有一个行内元素挂件(作者 j 字母打头),还有一个据说很好用的相关插件(好像叫关键信息导航)(侧边 dock 聚合),楼主可以去看看。

    以上仅限于尝试帮助楼主解决当前问题。思源优化和技术讨论不包含在内。

    用 type = p 应该就可以做到——做不到。type = 'p' 没用
    1ssss
  • 绝对是 SQL 写的不对,直接把示例文档发一下、查询需求说一下。

    另外 AI 味太重了,会把简单的问题变复杂,实在是看不懂在说什么了。

  • 再 ps,太长不看的另一个原因在于你这篇“原创指数 100”的文章处处都充满了 AI 写作的痕迹,而未经自己思考和初步处理。无论是危言耸听的标题,这个《提问的智慧》框架,内部那两句甚至未经处理的“[此处插入那张……的截图]”,甚至是最后充满情绪的吐槽。

    它的本质是 AI 回答摘录的组合拼接,因此整篇文章显得功能实现上的求助、期望技术底层优化的建议和花费半天而未能收获到预期成果的负面情绪抱怨的混合体,还是 AI 出品。

    作为一个潜在的、无偿的、被求助对象,我期待看到的清晰的问题和需求描述,至少有图片证明你经过尝试或验证(哪怕是一个因为图片太长,无法截图的简短说明),以及不接收你个人的负面情绪。AI 可以辅助你写作,但“未经自己思考和初步处理的 AI 回答摘录拼接”并没有让我觉得自己被尊重。我回答并试图提供帮助,是且仅仅是因为我知道“花费半天而未能收获到预期成果”有多难受。

    楼主之前的求助贴写得就蛮清爽的。AI 可以用作思路的辅助,但别真把自己当成 AI 人用。下次还是按原先的写法写吧。

    1 回复
  • 感谢各位老哥的批评,确实是我犯懒了,直接把 AI 生成的总结发出来,没考虑到大家的阅读体验,抱歉。
    我的核心需求非常简单: 我习惯用 Alt+X 给大纲列表里的某一行(列表项)上色标记重点。 我想在文档顶部,用 SQL 把本文档内所有标了颜色的这一行字汇总展示出来。
    遇到的卡点:
    用 SQL 查 ial 颜色属性,因为我标的是列表项(容器),思源会强制把这一行下面 【或者上面】的所有子节点(笔记正文)全显示出来,导致结果很乱。
    我想实现:“只显示标绿的那一行字,不要显示它下面的子内容”。
    请问如果不使用插件,原生 SQL 有办法做到“只渲染父级内容”吗? 如果原生做不到,我就去研究大家推荐的 Query View 和关键信息导航插件了。感谢指路!

    @@participants

    1 回复
  • 导出一个最简的示例文档看看

    发帖子下面了哈。
    1ssss
  • shaoxia 1 赞同

    这还是 ai 写的。。。。

    1 回复
  • 1ssss 1 评论

    怎么说呢?我觉得挺清晰的。😂

    我的要求就是把一个文档里面,我所有标绿的块都给筛选出来。就这么简单的需求。

    【使用场景:现在用 AI 很多,AI 很多分析,我只想要把我重视的信息汇总起来。但是我又不想把过程文档全部删除。我希望我看到一些信息很好,就直接 alt+X 标绿,然后在文档末尾处使用查询 汇总起来。
    为何是 alt+X 呢?因为只有 alt+X 是思源原生支持跨块选中一键标绿的。其他的都有些麻烦。】

    但是实际上尝试用 SQL 查询,就总是会筛选到上级标题 下级节点。没有标绿的都会被筛选到。搞了十几个代码总是无法解决,头疼。
    搞替代方案的话 你说的块自定义标注是一个 标签是一个 ,标记后 用 汇总行级元素 也是一个方法。 就是感觉差点意思。
    感觉理论上思源用 SQL 语法可以直接查询,很简单的样子,但是却一直搞不定。头疼。

    他不是在回复你
    JeffreyChen
  • 天哪!我成了 我成了!!!!!!

    用的是 query view 代码如下


    PixPin20251214134505.png

    只查询标绿

    //!js
    const query = async () => {
        // 1. 初始化 (严格照抄你的例子2)
        let dv = Query.DataView(protyle, item, top);
        const currentId = Query.root_id(dv.protyle);
    
        // 2. 目标颜色 (绿色)
        const targetColor = "var(--b3-card-success-background)";
    
        // 3. SQL 查询
        const sql = `
            SELECT * FROM blocks 
            WHERE root_id = '${currentId}' 
            AND ial LIKE '%${targetColor}%'
            ORDER BY sort ASC
        `;
      
        let blocks = await Query.sql(sql);
    
        // 4. 渲染逻辑
        if (blocks.length === 0) {
            dv.addmd("> *No highlights found.*");
        } else {
            // 【关键修正】
            // 不用 dv.header,直接用 Markdown 语法写标题
            // 遍历 blocks,只提取 aslink (原子链接),拼接成无序列表
            const mdContent = "### 🟢 S1 核心要义聚合\n" + 
                              blocks.map(b => `- ${b.aslink}`).join('\n');
          
            dv.addmd(mdContent);
        }
    
        dv.render();
    }
    
    return query();
    

    标绿中间划线隔开

    //!js
    // 1. 定义单行渲染模板 (参考你的例子2)
    // 这里只取 b.aslink,确保不带出子节点
    const row = (b) => `
    {{{col
    **${b.aslink}**
    {: style="flex: 1;" }
    }}}
    {: style="border-bottom: 1px dashed var(--b3-theme-on-surface-light); padding: 8px 0;" }
    `.trim();
    
    const query = async () => {
        let dv = Query.DataView(protyle, item, top);
        const currentId = Query.root_id(dv.protyle);
        const targetColor = "var(--b3-card-success-background)";
    
        const sql = `
            SELECT * FROM blocks 
            WHERE root_id = '${currentId}' 
            AND ial LIKE '%${targetColor}%'
            ORDER BY sort ASC
        `;
      
        let blocks = await Query.sql(sql);
    
        if (blocks.length === 0) {
            dv.addmd("> *当前文档无绿色标记*");
        } else {
            // 【关键修正】用 addmd 渲染标题 + 内容
            // 标题
            dv.addmd("### 🟢 S1 核心 Dashboard");
          
            // 内容:把所有块通过 row 函数处理,然后用换行符连接
            dv.addmd(blocks.map(row).join('\n'));
        }
    
        dv.render();
    }
    
    return query();
    

    全色块查询/信息 成功 警告 错误汇总

    //!js
    // 1. 定义颜色配置 (用于识别和上色)
    const colorMap = {
        "success": { 
            bg: "var(--b3-card-success-background)", 
            border: "var(--b3-card-success-color)" 
        },
        "warning": { 
            bg: "var(--b3-card-warning-background)", 
            border: "var(--b3-card-warning-color)" 
        },
        "error":   { 
            bg: "var(--b3-card-error-background)",   
            border: "var(--b3-card-error-color)" 
        },
        "info":    { 
            bg: "var(--b3-card-info-background)",  
            border: "var(--b3-card-info-color)" 
        }
    };
    
    // 2. 定义单行渲染模板
    const row = (b) => {
        // 自动检测当前块属于哪种颜色,决定边框颜色
        let borderColor = "var(--b3-theme-on-surface-light)"; // 默认灰色
      
        // 遍历查找匹配的颜色
        for (let type in colorMap) {
            if (b.ial && b.ial.includes(colorMap[type].bg)) {
                borderColor = colorMap[type].border;
                break;
            }
        }
    
        // 渲染:只取 aslink (原子链接),并加上对应颜色的底边框
        return `
    {{{col
    **${b.aslink}**
    {: style="flex: 1;" }
    }}}
    {: style="border-bottom: 2px solid ${borderColor}; padding: 6px 0;" }
    `.trim();
    };
    
    const query = async () => {
        let dv = Query.DataView(protyle, item, top);
        const currentId = Query.root_id(dv.protyle);
    
        // 3. 构建 SQL 的 OR 条件
        // 生成类似: ial LIKE '%success%' OR ial LIKE '%warning%' ...
        const conditions = Object.values(colorMap)
            .map(c => `ial LIKE '%${c.bg}%'`)
            .join(' OR ');
    
        const sql = `
            SELECT * FROM blocks 
            WHERE root_id = '${currentId}' 
            AND (${conditions})
            ORDER BY sort ASC
        `;
      
        let blocks = await Query.sql(sql);
    
        if (blocks.length === 0) {
            // 如果没数据,显示灰色提示
            dv.addmd("> *当前文档无 S1 标记 (绿/黄/红/蓝)*");
        } else {
            // 标题
            dv.addmd("### 🌈 S1 全光谱 Dashboard");
            // 渲染列表
            dv.addmd(blocks.map(row).join('\n'));
        }
    
        dv.render();
    }
    
    return query();
    

    感谢大家建议

    从 SQL 里面出来了,SQL 可能做不到这点。【如果 SQL 能做到的话麻烦安利一下哈 毕竟 js 有点复杂的样子。】

    js 做到了。

    1 回复
  • 说实话我还是没看懂你想实现的效果,为什么不想被查询的也要显示,不过既然你觉得能用了那我就不管了

    1.我想实现:只查询只显示我标记块。 但是实际上在思源用 SQL 查询的时候,会把我没标记的块也给查询显示出来。用各种代码都不行。所以我才发了这个帖子。 现在总之用 JS 解决了,大概用 SQL 难以解决吧。
    1ssss
    @1ssss 如果只是查块而不是查文本,SQL 肯定是能解决的,只不过我看不太懂你的需求,所以就算了
    JeffreyChen
    @JeffreyChen 要不你试一下?把我帖子里面的通用测试.sy.zip 当做测试。写一个 SQL,只查询里面有颜色标注的块。 这个 SQL 卡了我好久来着,我想看到它被解决。
    1ssss
  • PixPin20251216231443.png

    这个 SQL 代码不行哈。还是会出现我帖子里说的问题:会把不相关的给查询出来。

    SELECT * FROM blocks 
    WHERE ial LIKE '%color%'
    UNION
    SELECT b.* FROM blocks b
    INNER JOIN spans s ON b.id = s.block_id
    WHERE s.ial LIKE '%color%'
    
    
    1 回复
  • 至少我这里没问题:

    PixPin20251217005029.jpg

    用这个可以限制查询的文档:

    SELECT * FROM blocks b
    WHERE b.root_id = '20251214091335-5rv2wia'
    AND (
        b.ial LIKE '%color%'
        OR EXISTS (
            SELECT 1 FROM spans s 
            WHERE s.block_id = b.id 
            AND s.ial LIKE '%color%'
        )
    )
    
    1 回复
  • 我测试了一下,你这个查询还是有问题。

    1. 一开始我直接在主空间进行测试,你的代码还是老问题。没解决。但是你的截图很明显是正确的结果,我尝试排查问题
    2. 我为了测试,新建一个工作空间,那新建空间里面,导入你的 sy.zip 查询没有问题。这个 SQL 语法在新建空间没有问题。
    3. 但是我把这个查询代码在我主空间运行 就还是老问题。
    4. 为了排查问题,我在主空间把所有插件关闭,主题切换到默认白天,所有代码 css js 关闭。重新启动之后,还是无法实现在新建空间的效果。
    5. 我把主空间的测试文档导出 导入到 新建空间,发现这个问题不会修复。不会因为到了新建空间而修复。
    6. 我把新建空间的看起来没问题的测试文档导入到主空间,发现问题了,旧的查询块刷新后 还是没问题。但是一旦我用和旧的查询块 一样的代码,新建查询进行测试的时候,问题复现了。 哪怕把旧查询删除,也还是无用。录制视频如下
    7. 思源版本当前版本 v3.5.0
    8. 重新在新建空间进行 SQL 代码测试,问题出现。最早的正常情况无法复现 😭
    9. 我把我的思源文档导出 里面有截图,附上。查询带颜色的块主空间.sy.zip

    截图以及视频如下:PixPin20251217095134.png

    PixPin20251217091937.png

    1 回复
  • 我给你的文档里不是已经说明了要切换这个设置吗,你都没动:

    PixPin20251217104947.jpg

    1 回复
    是这个设置。因为我一开始测试的是你给我的第一个代码,那个代码不行,切换这个设置后也没用。所以第二个代码测试的时候我忽略了这个问题。现在确认你第二个代码 + 切换仅显示标题块 这个设置可用。 非常感谢!
    1ssss
  • 感谢 JeffreyChen 提供的这个 SQL 方案,非常简洁明了。👍 👍 👍

    完整方案如下

    SELECT * FROM blocks b
    WHERE b.root_id = '20251214091335-y0pudi9'
    AND (
        b.ial LIKE '%color%'
        OR EXISTS (
            SELECT 1 FROM spans s 
            WHERE s.block_id = b.id 
            AND s.ial LIKE '%color%'
        )
    )
    
    

    用的时候改一下查询文档的 ID 就行

    并且一定要把嵌入块设置 调节为:仅显示标题块。否则的话还是会查询到没有标记的块。

    PS:这个仅显示标题块 让你难以理解意思。很神奇的一个设置。

    PixPin20251217182720.png

    最后,我的几个 JS 方案也是可行的。按需选取。

    1 回复
  • 因为默认会把查询到的标题块下方的块一起显示出来,所以要限制显示范围

请输入回帖内容 ...