如何使用子查询作为黑名单排除查询中的结果
How to exclude results in a query using a subquery as blacklist
我正在尝试查询数据库中的文本,使用(子)查询作为“黑名单”。扭曲:如果主查询的任何结果与子查询的任何结果具有相同的开头,则应跳过它们。
一些背景知识:我正在构建一个文件浏览器,并使用 table 文件夹名称来维护条目的“收藏”状态。这些收藏旨在以级联方式工作,即“明确”收藏路径下方的任何路径都将“隐式”收藏。
考虑以下数据:
foldername
is_favorite
is_implicit_favorite
foo/
1
0
foo/bar/
1
1
foo/bar/baz/
0
1
foo/bar2/
0
1
foo/bar2/baz/
0
1
foo2/bar/
0
0
foo2/bar/baz/
0
0
添加收藏夹很容易:给定路径下的所有文件夹都将设置其“隐式”状态。但我发现很难想出一个简单的相反方法——“取消收藏”一个文件夹。因为在这里,我希望查询跳过应该保持隐式收藏的文件夹(在上面的示例中,取消收藏“foo/”应该跳过“foo/bar”下面的文件夹)。
我尝试了各种解决方案 - 以下方法很接近,但不幸的是只适用于 单个 最喜欢的子文件夹:
SELECT DISTINCT folders.foldername FROM folders
JOIN (
SELECT folders.foldername FROM folders
WHERE folders.foldername LIKE 'foo/' || '%'
AND folders.is_favorite = 1
) favs ON folders.foldername NOT LIKE favs.foldername || '%'
WHERE folders.foldername LIKE 'foo/' || '%'
它做我想做的事——不喜欢“foo”应该导致“foo/bar2/”和“foo/bar2/baz/”不再被隐式收藏,而“foo/bar/"(及其子文件夹)保持不变:
folders.foldername
foo/
foo/bar2/
foo/bar2/baz/
在线查看:
http://sqlfiddle.com/#!5/8a04e/14/0
编辑:感谢基督徒的回答将我指向 EXCEPT 运算符,我能够想出以下修改后的版本,该版本也适用于多个收藏夹。
SELECT folders.foldername FROM folders
WHERE folders.foldername LIKE 'foo/' || '%'
EXCEPT
SELECT folders.foldername FROM folders
INNER JOIN (
SELECT folders.foldername FROM folders
WHERE folders.foldername <> 'foo/'
AND folders.is_favorite = 1
) favs
ON folders.foldername LIKE favs.foldername || '%'
我很高兴甚至可以用纯 SQL 来表达这一点 - 我曾短暂地想将它变成一个混合 SQL/node.js 解决方案。
当然,我很乐意接受任何可能的优化建议!
谢谢。
如果你有 PostgreSQL 数据库,你可以使用这个:
SELECT folders.foldername FROM folders WHERE folders.foldername LIKE 'foo/%'
EXCEPT ALL
SELECT folders.foldername FROM folders
WHERE folders.foldername LIKE 'foo/%' AND folders.is_favorite = 1
这可能不是最有效的查询,但它可以解决问题:
SELECT folders.foldername FROM folders
WHERE folders.foldername LIKE 'foo/' || '%'
EXCEPT
SELECT folders.foldername FROM folders
INNER JOIN (
SELECT folders.foldername FROM folders
WHERE folders.foldername <> 'foo/'
AND folders.is_favorite = 1
) favs
ON folders.foldername LIKE favs.foldername || '%'
(更新了我原来的post)
我正在尝试查询数据库中的文本,使用(子)查询作为“黑名单”。扭曲:如果主查询的任何结果与子查询的任何结果具有相同的开头,则应跳过它们。
一些背景知识:我正在构建一个文件浏览器,并使用 table 文件夹名称来维护条目的“收藏”状态。这些收藏旨在以级联方式工作,即“明确”收藏路径下方的任何路径都将“隐式”收藏。
考虑以下数据:
foldername | is_favorite | is_implicit_favorite |
---|---|---|
foo/ | 1 | 0 |
foo/bar/ | 1 | 1 |
foo/bar/baz/ | 0 | 1 |
foo/bar2/ | 0 | 1 |
foo/bar2/baz/ | 0 | 1 |
foo2/bar/ | 0 | 0 |
foo2/bar/baz/ | 0 | 0 |
添加收藏夹很容易:给定路径下的所有文件夹都将设置其“隐式”状态。但我发现很难想出一个简单的相反方法——“取消收藏”一个文件夹。因为在这里,我希望查询跳过应该保持隐式收藏的文件夹(在上面的示例中,取消收藏“foo/”应该跳过“foo/bar”下面的文件夹)。
我尝试了各种解决方案 - 以下方法很接近,但不幸的是只适用于 单个 最喜欢的子文件夹:
SELECT DISTINCT folders.foldername FROM folders
JOIN (
SELECT folders.foldername FROM folders
WHERE folders.foldername LIKE 'foo/' || '%'
AND folders.is_favorite = 1
) favs ON folders.foldername NOT LIKE favs.foldername || '%'
WHERE folders.foldername LIKE 'foo/' || '%'
它做我想做的事——不喜欢“foo”应该导致“foo/bar2/”和“foo/bar2/baz/”不再被隐式收藏,而“foo/bar/"(及其子文件夹)保持不变:
folders.foldername |
---|
foo/ |
foo/bar2/ |
foo/bar2/baz/ |
在线查看: http://sqlfiddle.com/#!5/8a04e/14/0
编辑:感谢基督徒的回答将我指向 EXCEPT 运算符,我能够想出以下修改后的版本,该版本也适用于多个收藏夹。
SELECT folders.foldername FROM folders
WHERE folders.foldername LIKE 'foo/' || '%'
EXCEPT
SELECT folders.foldername FROM folders
INNER JOIN (
SELECT folders.foldername FROM folders
WHERE folders.foldername <> 'foo/'
AND folders.is_favorite = 1
) favs
ON folders.foldername LIKE favs.foldername || '%'
我很高兴甚至可以用纯 SQL 来表达这一点 - 我曾短暂地想将它变成一个混合 SQL/node.js 解决方案。
当然,我很乐意接受任何可能的优化建议!
谢谢。
如果你有 PostgreSQL 数据库,你可以使用这个:
SELECT folders.foldername FROM folders WHERE folders.foldername LIKE 'foo/%'
EXCEPT ALL
SELECT folders.foldername FROM folders
WHERE folders.foldername LIKE 'foo/%' AND folders.is_favorite = 1
这可能不是最有效的查询,但它可以解决问题:
SELECT folders.foldername FROM folders
WHERE folders.foldername LIKE 'foo/' || '%'
EXCEPT
SELECT folders.foldername FROM folders
INNER JOIN (
SELECT folders.foldername FROM folders
WHERE folders.foldername <> 'foo/'
AND folders.is_favorite = 1
) favs
ON folders.foldername LIKE favs.foldername || '%'
(更新了我原来的post)