筛查指路径和指定列表的任务
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 定位元素的标志。
不知是否是你想要的需求,我简单测试了下没发现问题,不知是否存在潜在问题,如果有问题可以随时反馈。
效果:
筛选任务状态
如果需要筛选 [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
)都加入到了结果集中,这就是递归操作带来的结果集的变化,实现了从一个或多个起始节点向下查找所有相关后代节点的效果。
如果在实际情况中,你的表结构更复杂、数据更多,按照同样的逻辑,会不断地把符合条件的后代记录一层一层地添加进来,直到没有新的子记录可添加为止。
