2017-10-16 73 views
0

我有一個很奇怪的問題與sqlite3的 - 運行sqlite3的3.20.1版本的Windows。SQLite的力排序上選擇

在兩個不同的表同樣的SELECT查詢產生不同的結果。但是列數據類型和數據在兩者中都是相同的。這裏是CREATE和INSERT語句。

CREATE TABLE key(key INTEGER UNIQUE NOT NULL); 
CREATE TABLE map(key INTEGER UNIQUE NOT NULL, char TEXT); 

WITH RECURSIVE cnt(x) AS (SELECT 1 UNION ALL SELECT x+1 FROM cnt LIMIT 9999) INSERT INTO key(key) SELECT x FROM cnt WHERE x >=1000 ORDER BY random(); 
WITH RECURSIVE cnt(x) AS (SELECT 1 UNION ALL SELECT x+1 FROM cnt LIMIT 9999) INSERT INTO map(key) SELECT x FROM cnt WHERE x >=1000 ORDER BY random(); 

這應該插入隨機排序成兩列,從1000到9999的數字。但是,第二個表上的SELECT語句總是排序的。這是結果

sqlite> SELECT key FROM map LIMIT 10; 
1000 
1001 
1002 
1003 
1004 
1005 
1006 
1007 
1008 
1009 
sqlite> SELECT key FROM key LIMIT 10; 
6165 
1856 
2457 
2343 
9095 
8005 
4958 
4781 
8334 
1863 

我甚至嘗試了以下;

sqlite> DELETE FROM map; 
sqlite> INSERT INTO map(key) SELECT key FROM key; 
sqlite> 
sqlite> SELECT key FROM map LIMIT 10; 
1000 
1001 
1002 
1003 
1004 
1005 
1006 
1007 
1008 
1009 

它仍然排序!使用REPLACE也沒有幫助。 我試過甚至通過先添加id列來改變表格模式,但也沒有成功。

經過一番實驗後,我發現SELECT *顯示它在正確的順序,但SELECT key給出了有序的結果。

sqlite> SELECT * FROM map LIMIT 10; 
8418| 
5869| 
9753| 
2886| 
8354| 
8244| 
4063| 
6692| 
5440| 
3508| 

你能解釋一下嗎?它是一個錯誤還是一個功能?我怎樣才能得到預期的輸出?

回答

0

documentation說:

如果返回多行SELECT語句不具有ORDER BY子句,行返回的順序是未定義的。

如果您想查詢以隨機順序返回行,你必須在查詢本身使用ORDER BY random()

(要在內部順序返回行,可使用ORDER BY rowid,但這並不對WITHOUT ROWID tables工作。)


對於唯一約束的索引使用更少的存儲空間,則表,因爲它只包含一個列。 所以只要你想只讀此列,查詢優化器更傾向於直接從指數(作爲covering index)讀取的值,因爲從磁盤讀取數據較少,使查詢速度更快:

sqlite> EXPLAIN QUERY PLAN SELECT key FROM map; 
0|0|0|SCAN TABLE map USING COVERING INDEX sqlite_autoindex_map_1 

那返回的行然後碰巧被排序只是一個副作用。

+0

非常感謝。很有幫助! – Dawood

+0

添加'ORDER BY ROWID'給出預期的結果。 – Dawood

0

這應該插入隨機排序成兩列,從1000到9999的數字。但是,第二個表上的SELECT語句總是排序的。

你不懂SQL。 SQL表格代表無序集合。這意味着SQL引擎可以決定如何存儲它想要的數據。

SQL查詢返回無序套。這意味着SQL引擎可以決定結果集的排序 - 除非您指定了排序。

在這種情況下,SQLite是基於表的唯一鍵,返回結果集 - 它使用的查詢索引。 (SQLite的可能實際上是決定了唯一鍵是表的主鍵)

+0

謝謝。但是,如果'select *'結果與'select column'不同,如果它是由相同的「主鍵」命令的呢? 你也可以爲這種行爲添加一個參考嗎? – Dawood

+0

@達伍德。 。 。它將在一種情況下使用唯一索引,而在另一種情況下使用唯一索引。如果你想以特定的順序輸入數據,那麼使用'order by'。 –