【发布时间】:2013-03-14 18:32:10
【问题描述】:
我想查询一个包含目录路径的 SQLite 表,以查找某个层次结构下的所有路径。以下是该列内容的示例:
/alpha/papa/
/alpha/papa/tango/
/alpha/quebec/
/bravo/papa/
/bravo/papa/uniform/
/charlie/quebec/tango/
如果我搜索/bravo/papa/ 下的所有内容,我想得到:
/bravo/papa/
/bravo/papa/uniform/
我目前正在尝试这样做(关于为什么我不能使用更简单的方法的长篇故事,请参见下文):
SELECT * FROM Files WHERE Path >= '/bravo/papa/' AND Path < '/bravo/papa0';
这行得通。它看起来有点奇怪,但它适用于这个例子。 '0' 是大于 '/' 的 unicode 代码点 1。当按字典顺序排序时,所有以 '/bravo/papa/' 开头的路径都比较大于它和小于 'bravo/papa0'。但是,在我的测试中,我发现当我们尝试这样做时会出现问题:
SELECT * FROM Files WHERE Path >= '/' AND Path < '0';
这不会返回任何结果,但它应该返回每一行。据我所知,问题在于 SQLite 将 '0' 视为数字,而不是字符串。例如,如果我使用“0Z”而不是“0”,我确实会得到结果,但会带来误报的风险。 (例如,如果确实有一个条目“0”。)
我的问题的简单版本是:有什么方法可以让 SQLite 在这样的查询中将“0”视为包含 unicode 字符“0”的长度为 1 的字符串(应该对字符串进行排序,例如“!” 、'*' 和 '/',但在 '1'、'=' 和 'A' 之前)而不是整数 0(SQLite 在所有字符串之前排序)?
我认为在这种情况下,我实际上可以通过特殊情况搜索“/”下的所有内容,因为我的所有条目都将始终以“/”开头,但我真的很想知道如何避免这种情况一般而言,它与 Javascript 的 "==" 运算符一样令人不快。
第一种方法
更自然的方法是使用 LIKE 或 GLOB 运算符。例如:
SELECT * FROM Files WHERE Path LIKE @prefix || '%';
但我想支持所有有效的路径字符,所以我需要对“_”和“%”符号使用 ESCAPE。显然这会阻止 SQLite 在 Path 上使用索引。 (请参阅http://www.sqlite.org/optoverview.html#like_opt)我真的希望能够从这里的索引中受益,这听起来像是使用 LIKE 或 GLOB 是不可能的,除非我可以保证它们的特殊字符都不会出现在目录名称中,并且 POSIX 允许除了 NUL 和 '/' 之外的任何内容,甚至 GLOB 的 '*' 和 '?'字符。
我提供这个作为上下文。我对解决潜在问题的其他方法很感兴趣,但我更愿意接受一个直接解决 SQLite 中类似数字的字符串的歧义的答案。
类似问题
How do I prevent sqlite from evaluating a string as a math expression?
在那个问题中,没有引用这些值。即使值被引用或作为参数传入,我也会得到这些结果。
编辑 - 请参阅下面的答案。该列是使用无效类型“STRING”创建的,SQLite 将其视为 NUMERIC。
【问题讨论】:
-
为我工作。
Path列是如何定义的? -
@CL。我很确定它被定义为 TEXT 列,但它现在不在我面前。明天我会检查并用比和 SQLite 版本号更新问题。
-
我不确定这是否可行,但是像
WHERE 'X' || Path > 'X' || '/bravo/papa/' AND 'X' || '/bravo/papa0'这样的东西呢?或者如果可能,首先将变量分配给'X' || Path的值。 -
我会试试的,虽然我不确定它是否仍能使用索引。但是,我已经在我的 Linux 笔记本电脑上尝试了查询,并且它的工作方式与我最初希望的 CL 一样。报告,所以我在 Windows 机器上的原始数据库肯定有其他问题。我明天更新。
-
我也有这个问题。我所有的字符串列都被定义为 STRING 而不是 TEXT。工作正常,直到我尝试插入看起来像“1.4e-1”的东西,sqlite 愉快地变成了 0.14 。我希望 sqlite 引擎在声明不存在的类型(如 STRING)的亲和性时会引发某种异常。
标签: sqlite