筛查指路径和指定列表的任务

筛查指路径和指定列表的任务

see https://ld246.com/article/1734858211967

筛选指定路径和指定列表的任务

如果仅用 SQL 实现的话,主要带有子任务的父任务不好处理。

我这里通过取巧的方式实现了仅 SQL 查询,需要一段 css 配合一下,原理就是把指定 SQL 的子任务给隐藏起来。

SQL1:在路径内随机索引单个任务项

-- random-task-hpath 这里的注释不要删除且必须再第一行且必须--开头且不能有空格
SELECT * FROM blocks
WHERE (
    -- 👇这里可以添加更多路径,可在目录右键复制可读路径获取
    hpath like '%/daily note/2024/12/111%'
    OR hpath like '%/daily note/2024/12/111%'
)
AND type = 'i'
AND subtype = 't'
-- 这里可以修改任务状态👇,注意[X]中的X必须是大写,[ ]中有个英文空格,可以复制这注释里的
AND markdown like '%* [ ] %'  || TRIM(fcontent) || '%'
ORDER BY RANDOM()
LIMIT 1;

SQL2:在列表内随机索引单个任务项

-- radmom-task-list 这里的注释不要删除且必须再第一行且必须--开头且不能有空格
WITH RECURSIVE Descendants AS (
    -- 非递归部分,这是起始查询,选择指定id的初始记录
    SELECT *
    FROM blocks
    WHERE id in(
        -- 👇这里可以添加更多列表id
        '20241222170944-o65g6ol', 
        '20241222170955-k3mt4vd'
    )
    UNION ALL
    -- 递归部分,将子记录不断加入结果集
    SELECT b.*
    FROM blocks b
         JOIN Descendants d ON b.parent_id = d.id
)
SELECT * FROM Descendants
WHERE type = 'i'
AND subtype = 't'
-- 这里可以修改任务状态👇,注意[X]中的X必须是大写,[ ]中有个英文空格,可以复制这注释里的
AND markdown like '%* [ ] %'  || TRIM(fcontent) || '%'
ORDER BY RANDOM()
LIMIT 1;

css 代码:

/* 隐藏指定SQL的嵌入块中的子任务 */
[data-type="NodeBlockQueryEmbed"][data-content^="-- random-task-hpath"],
[data-type="NodeBlockQueryEmbed"][data-content^="-- radmom-task-list"]{
    [data-subtype="t"]:not([data-marker="*"]) {
        display:none;
    }
}

说明:SQL 前面的 -- random-task-hpath​ 和 -- radmom-task-list​ 注释不要删除,这是 css 定位元素的标志。

不知是否是你想要的需求,我简单测试了下没发现问题,不知是否存在潜在问题,如果有问题可以随时反馈。

效果:

image.png

筛选任务状态

如果需要筛选 [X]​ 和 [ ]​ 状态可以按照下面的方式添加到条件里即可。
添加到这两个条件后面就行
WHERE type = 'i'
AND subtype = 't'

比如

select * from blocks
-- (其他SQL)
WHERE type = 'i'
AND subtype = 't'
-- 匹配已选中的
AND markdown like '* [X]%'
-- 匹配未选中的
AND markdown like '* [ ]%'
-- 以上SQL一般没有问题,仅匹配第一个任务,能有效避免误选子任务
-- 如果有问题,也可以用下面的方式,更安全,但稍麻烦
-- 匹配已选中的,注意[X]中的X必须是大写,[ ]中有个英文空格
AND markdown like '%* [X] %'  || TRIM(fcontent) || '%'
-- 匹配未选中的,注意[X]中的X必须是大写,[ ]中有个英文空格
AND markdown like '%* [ ] %'  || TRIM(fcontent) || '%'
ORDER BY RANDOM()
LIMIT 1;

SQL的UNION ALL原理说明

例如,假设我们有如下简单的 blocks​ 表数据(为了方便示例简化了数据结构和实际值,用数字表示 id​ 和 parent_id​ 等):

id parent_id type subtype content
1 0 'i' 't' 'a'
2 1 'i' 't' 'b'
3 2 'i' 't' 'c'
4 0 'x' 'y' 'd'

并且我们设定起始查询的 id​ 列表为 (1)​(就像你代码里实际指定那两个复杂 id​ 一样,这里简化为 1​ 方便举例)。

  • 第一步:非递归部分会找到 id​ 为 1​ 的记录,也就是 (1, 0, 'i', 't', 'a')​ 这条记录,这是起始节点。
  • 第二步:进入递归部分,此时 Descendants​ 里就只有刚才找到的 id​ 为 1​ 的那条记录。然后查询会去 blocks​ 表中找 parent_id​ 等于 1​ 的记录,会找到 id​ 为 2​ 的记录(因为它的 parent_id​ 是 1​),这样 id​ 为 2​ 的记录就被加入到 Descendants​ 结果集中了,此时 Descendants​ 包含 id​ 为 1​ 和 2​ 的记录。
  • 第三步:再次进行递归查找,因为 Descendants​ 现在有 id​ 为 1​ 和 2​ 的记录了,会继续查找 blocks​ 表中 parent_id​ 为 2​ 的记录(基于刚才新加入的 id​ 为 2​ 的记录),会找到 id​ 为 3​ 的记录并加入到 Descendants​ 中,现在 Descendants​ 包含 id​ 为 1​、2​、3​ 的记录了。
  • 第四步:继续递归查找,发现没有新的符合 parent_id​ 匹配条件的记录了,递归结束,Descendants​ 最终包含了 id​ 为 1​、2​、3​ 的记录,这就是以 id​ 为 1​ 的记录为起始节点的所有后代记录。

递归后的结果集是什么,与递归前有什么不同?

以下是以之前假设的 blocks​ 表数据为例,展示递归前后结果集的情况:

递归前(非递归部分找到的起始节点)

在非递归部分,我们设定起始查询的 id​ 为 1​,所以找到的起始节点记录如下表所示:

id parent_id type subtype content
1 0 'i' 't' 'a'

递归后(最终 Descendants​ 结果集)

经过递归查找所有后代节点的操作后,Descendants​ 结果集如下表所示:

id parent_id type subtype content
1 0 'i' 't' 'a'
2 1 'i' 't' 'b'
3 2 'i' 't' 'c'

可以看出,递归前只有最初指定的起始节点记录(id​ 为 1​ 的那条),而递归后通过不断查找子记录(基于 parent_id​ 和已有记录 id​ 的关联匹配),将 id​ 为 1​ 的记录的所有后代记录(这里是 id​ 为 2​ 和 3​ 的记录,因为 2​ 的父节点是 1​,3​ 的父节点是 2​)都加入到了结果集中,这就是递归操作带来的结果集的变化,实现了从一个或多个起始节点向下查找所有相关后代节点的效果。

如果在实际情况中,你的表结构更复杂、数据更多,按照同样的逻辑,会不断地把符合条件的后代记录一层一层地添加进来,直到没有新的子记录可添加为止。

image.png

留下你的脚步
推荐阅读