我有SQLite數據庫,並且在其中有一些類型爲「double」的特定列。 我想獲得最接近指定值的列值。SQLite - 獲得最接近的價值
例如,在我的表,我有:
id: 1; value: 47
id: 2; value: 56
id: 3; value: 51
而且我希望得到一個行中具有其值最接近50所以我想收到ID:3(值= 51)。
我該如何實現這個目標?
謝謝。
我有SQLite數據庫,並且在其中有一些類型爲「double」的特定列。 我想獲得最接近指定值的列值。SQLite - 獲得最接近的價值
例如,在我的表,我有:
id: 1; value: 47
id: 2; value: 56
id: 3; value: 51
而且我希望得到一個行中具有其值最接近50所以我想收到ID:3(值= 51)。
我該如何實現這個目標?
謝謝。
這應該工作:
SELECT * FROM table
ORDER BY ABS(? - value)
LIMIT 1
其中?
代表要比較的值。
它顯然會工作,但它實際上是優化工作在`log N`時間? – ybungalobill 2014-07-02 16:16:01
@ybungalobill我非常懷疑任何優化器都能夠弄清楚如何最優地確定哪些鍵會爲ABS(? - 值)表達式產生最小的答案。 – Alnitak 2014-07-02 16:59:08
通過使用順序,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
您可以使用這樣的指標得到一個更低或更高值:
select min(value) from 'table' where x >= N;
select max(value) from 'table' where x <= N;
你也可以使用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)
即使在大型表格上,這也會相當快。你可以簡單地加載這兩個值,並在代碼中對其進行評估,或使用更多的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
或
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
既然你感興趣的值都大於任意並且小於目標,則無法避免進行兩次索引搜索。如果您知道目標是在小範圍內,但是,你可以使用「之間」只打一次索引:
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
這將是圍繞2X比聯合查詢時,只計算1以上的速度更快-2值,但如果你開始不得不加載更多的數據,它會很快變慢。
請記住,sqlite類型系統是特殊的,是否有一個真正的double與任何類型的聲明無關。 – unmounted 2009-04-11 09:35:29