如何防止SQLite将字符串视为数字?

Wee*_*ble 5 sqlite

我想查询一个包含目录路径的SQLite表,以查找某个层次结构下的所有路径。这是该列内容的示例:

/alpha/papa/
/alpha/papa/tango/
/alpha/quebec/
/bravo/papa/
/bravo/papa/uniform/
/charlie/quebec/tango/
Run Code Online (Sandbox Code Playgroud)

如果我搜索下的所有内容/bravo/papa/,则希望获得:

/bravo/papa/
/bravo/papa/uniform/
Run Code Online (Sandbox Code Playgroud)

我目前正在尝试这样做(请参阅下文,了解为什么我不能使用更简单的方法的长篇故事):

SELECT * FROM Files WHERE Path >= '/bravo/papa/' AND Path < '/bravo/papa0';
Run Code Online (Sandbox Code Playgroud)

这可行。看起来有点怪异,但适用于此示例。“ 0”是大于“ /”的Unicode代码点1。当按字典顺序排序时,所有以'/ bravo / papa /'开头的路径都比较大且小于'bravo / papa0'。但是,在我的测试中,我发现当我们尝试以下方法时,这种情况会分解:

SELECT * FROM Files WHERE Path >= '/' AND Path < '0';
Run Code Online (Sandbox Code Playgroud)

这不会返回任何结果,但是应该返回每一行。据我所知,问题在于SQLite将'0'视为数字,而不是字符串。例如,如果我使用“ 0Z”而不是“ 0”,则可以得到结果,但是会带来误报的风险。(例如,如果实际上有一个条目“ 0”。)

我的问题的简单版本是:有没有办法让SQLite在这样的查询中将'0'视为包含Unicode字符'0'的length-1字符串(应该对字符串进行排序,例如'!','* '和'/',但在'1','='和'A'之前而不是整数0(哪个SQLite在所有字符串之前排序)?

我认为在这种情况下,我实际上可以摆脱对“ /”下所有内容的特殊搜索,因为我的所有条目始终都以“ /”开头,但是我真的很想知道如何避免这种情况总的来说,与Javascript的“ ==”运算符完全一样,这令人不愉快。

第一种方法

一种更自然的方法是使用LIKE或GLOB运算符。例如:

SELECT * FROM Files WHERE Path LIKE @prefix || '%';
Run Code Online (Sandbox Code Playgroud)

但是我想支持所有有效的路径字符,因此我需要对'_'和'%'符号使用ESCAPE。显然,这阻止了SQLite在Path上使用索引。(请参阅http://www.sqlite.org/optoverview.html#like_opt)我真的希望能够从这里的索引中受益,并且听起来像使用LIKE或GLOB都是不可能的,除非我可以保证它们都不目录名称中将出现特殊字符,并且POSIX允许使用NUL和'/'以外的任何内容,甚至GLOB的'*'和'?' 字符。

我提供这个是为了上下文。我对解决潜在问题的其他方法感兴趣,但是我更愿意接受一个直接解决SQLite中字符串看起来像数字的歧义的答案。

类似问题

如何防止sqlite将字符串作为数学表达式求值?

在该问题中,未引用这些值。即使将值用引号引起来或作为参数传递,我也得到这些结果。


编辑 -请在下面查看我的答案。该列是使用无效类型“ STRING”创建的,SQLite将其视为NUMERIC。

Wee*_*ble 5

* Gro吟 *。该列具有NUMERIC关联性,因为它被意外地指定为“ STRING”而不是“ TEXT”。由于SQLite无法识别类型名称,因此将其命名为NUMERIC,并且由于SQLite不强制执行列类型,因此其他所有操作均按预期方式进行,除了每次将类似数字的字符串插入该列时,都会将其转换为数字类型。