2017-10-16 9 views
0

私は非常に奇妙な問題をsqlite3 - Windows用のsqlite3バージョン3.20.1を実行しています。SQLite強制的にソートSELECT

2つの異なるテーブルで同じ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の数字を挿入する必要があります。ただし、2番目のテーブルの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のために動作しないために。)UNIQUE制約のインデックスは、テーブルには、それは1つの列のみが含まれているため、より少ないストレージを使用しています


。ディスクからの少ないデータの読み取りが速い問い合わせを行うので、だから、限り、あなたは唯一のこのコラムを読んでもらいたいと、クエリオプティマイザは、(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の数字を挿入する必要があります。ただし、2番目のテーブルのSELECT文は常にソートされます。

あなたはSQLを理解していません。 SQLテーブルは、の順序付けされていないを表します。つまり、SQLエンジンはデータの保存方法を決めることができます。

SQLクエリは、の順不同でのセットを返します。つまり、注文を指定しない限り、SQLエンジンは結果セットの順序を決定できます。

この場合、SQLiteはテーブル内のユニークキーに基づいて結果セットを返します。これはクエリのインデックスを使用しています。 (。SQLiteのは、実際に一意のキーは、テーブルの主キーであると判断することができる)

+0

ありがとうございました。しかし、同じ「主キー」によって順序付けされる場合、 'select *'結果が 'select column'と異なるのはなぜですか? このような動作についても参考にしてください。 – Dawood

+0

@Dawood。 。 。あるケースではユニークインデックスを使用し、別のケースではデータページを使用します。特定の順序でデータが必要な場合は、 'order by'を使用します。 –

関連する問題