我有SQLite数据库,我在其中有一些类型为"double"的列.我想获得一个在此列值中最接近指定值的行.
例如,在我的表中我有:
id: 1; value: 47
id: 2; value: 56
id: 3; value: 51
Run Code Online (Sandbox Code Playgroud)
我想得到一个其值最接近50的行.所以我想收到id:3(value = 51).
我怎样才能实现这个目标?
谢谢.
Aln*_*tak 15
这应该工作:
SELECT * FROM table
ORDER BY ABS(? - value)
LIMIT 1
Run Code Online (Sandbox Code Playgroud)
Where ?代表您要比较的值.
Tim*_*ter 12
使用order-by,SQLite将扫描整个表并将所有值加载到临时b树中以对它们进行排序,从而使任何索引无效.这将非常慢并且在大型表上使用大量内存:
explain query plan select * from 'table' order by abs(10 - value) limit 1;
0|0|0|SCAN TABLE table
0|0|0|USE TEMP B-TREE FOR ORDER BY
Run Code Online (Sandbox Code Playgroud)
您可以使用索引获得下一个更低或更高的值,如下所示:
select min(value) from 'table' where x >= N;
select max(value) from 'table' where x <= N;
Run Code Online (Sandbox Code Playgroud)
您可以使用union从单个查询中获取两者:
explain query plan
select min(value) from 'table' where value >= 10
union select max(value) from 'table' where value <= 10;
1|0|0|SEARCH TABLE table USING COVERING INDEX value_index (value>?)
2|0|0|SEARCH TABLE table USING COVERING INDEX value_index (value<?)
0|0|0|COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION)
Run Code Online (Sandbox Code Playgroud)
即使在大型桌子上,这也会非常快.您可以简单地加载这两个值并在代码中对它们进行评估,或者使用更多的sql以各种方式选择一个:
explain query plan select v from
( select min(value) as v from 'table' where value >= 10
union select max(value) as v from 'table' where value <= 10)
order by abs(10-v) limit 1;
2|0|0|SEARCH TABLE table USING COVERING INDEX value_index (value>?)
3|0|0|SEARCH TABLE table USING COVERING INDEX value_index (value<?)
1|0|0|COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (UNION)
0|0|0|SCAN SUBQUERY 1
0|0|0|USE TEMP B-TREE FOR ORDER BY
Run Code Online (Sandbox Code Playgroud)
要么
explain query plan select 10+v from
( select min(value)-10 as v from 'table' where value >= 10
union select max(value)-10 as v from 'table' where value <= 10)
group by v having max(abs(v)) limit 1;
2|0|0|SEARCH TABLE table USING COVERING INDEX value_index (value>?)
3|0|0|SEARCH TABLE table USING COVERING INDEX value_index (value<?)
1|0|0|COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (UNION)
0|0|0|SCAN SUBQUERY 1
0|0|0|USE TEMP B-TREE FOR GROUP BY
Run Code Online (Sandbox Code Playgroud)
由于您对任意大于和小于目标的值感兴趣,因此您无法避免进行两次索引搜索.但是,如果你知道目标在一个小范围内,你可以使用"between"来只触及一次索引:
explain query plan select * from 'table' where value between 9 and 11 order by abs(10-value) limit 1;
0|0|0|SEARCH TABLE table USING COVERING INDEX value_index (value>? AND value<?)
0|0|0|USE TEMP B-TREE FOR ORDER BY
Run Code Online (Sandbox Code Playgroud)
当它仅评估1-2个值时,这将比上面的联合查询快2倍,但如果您开始加载更多数据,它将很快变慢.