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

时间:2013-03-13 16:48:04

标签: sqlite

我想查询包含目录路径的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。

1 个答案:

答案 0 :(得分:5)

* 呻吟 *。该列具有NUMERIC亲和力,因为它意外地被指定为“STRING”而不是“TEXT”。由于SQLite无法识别类型名称,因此它使其成为NUMERIC,并且由于SQLite不强制执行列类型,因此其他所有内容都按预期工作,除非每次将类似数字的字符串插入该列时它都会转换为数字类型。