2017-07-12 11 views
1

ID(整数)、N(整数)、V(実数)の3つの列を持つsqliteテーブルがあります。ペア(ID、N)は固有です。python sqlite3の再帰(カスケード)選択

Pythonモジュールsqlite3のを使用して、私は最大の再帰の深さを超過したためか、フォーム

select ID from TABLE where N = 0 and V between ? and ? and ID in 
    (select ID from TABLE where N = 7 and V between ? and ? and ID in 
     (select ID from TABLE where N = 8 and V between ? and ? and ID in 
      (...) 
     ) 
    ) 

私は次のエラーを取得すると、再帰的な選択を実行したいと思います(?)。私はまた、

select ID from 
     (select ID from TABLE where N = 0 and V between ? and ?) 
    join (select ID from TABLE where N = 7 and V between ? and ?) using (ID) 
    join (select ID from TABLE where N = 8 and V between ? and ?) using (ID) 
    join ... 

ようsubselectionsに参加しようとしたが、このアプローチはsupprisingly遅く、さらにいくつかのsubselectionsで

がより良い方法はあり

sqlite3.OperationalError: parser stack overflow 

約20〜50 recusionレベルを必要とします同じ選択を実行するには?
注:表が上にインデックスされる(N、V)は、以下

はIDは、(0であり、選択は

ID N V 
0 0 0,1 
0 1 0,2 
0 2 0,3 
1 0 0,5 
1 1 0,6 
1 2 0,7 
2 0 0,8 
2 1 0,9 
2 2 1,2 

ステップ0

select ID from TABLE where N = 0 and V between 0 and 0,6 

をどのように働くかを示すために一例であり、 1)
ステップ1

select ID from TABLE where N = 1 and V between 0 and 1 and ID in (0, 1) 

IDは
ステップ2

select ID from TABLE where N = 2 and V between 0,5 and 1 and ID in (0, 1) 

IDが1

+0

すべてのステップで 'V'境界が同じですか? 'N'値はどこから来ますか?すべてのステップからIDを取得しますか? –

+0

各ステップでV値が異なるわけではありません。この例では、Nの値は任意です。考え方は単に選択ステップをステップごとに細かく調整することです。 – user2660966

+0

一般的にいくつのステップがありますか?すべてのステップからIDを取得しますか? –

答えて

2

アンラップ再帰あり、逆の順序でそれを行うとPythonでそれを行う(0,1)のままです。このために、それぞれ0〜99のID、N = 3、V = 5の100個のレコードからなるテーブルを作成しました。僕はレコードのコレクション全体を一番内側に選んだ。

リストの先頭の値が最後のSQL SELECTのために選択されるように、インデックス付きNおよびVの値リストを持つと想像する必要があります。ループが行うことは、内部SELECTの結果であるIDのリストをIN句の一部として次のSELECTに渡すことです。

インデックスがない場合、これはオイゲンブルクで全面的に行われます。

>>> import sqlite3 
>>> conn = sqlite3.connect('recur.db') 
>>> c = conn.cursor() 
>>> previous_ids = str(tuple(range(0,100))) 
>>> for it in range(50): 
...  rows = c.execute('''SELECT ID FROM the_table WHERE N=3 AND V BETWEEN 2 AND 7 AND ID IN %s''' % previous_ids) 
...  previous_ids = str(tuple([int(_[0]) for _ in rows.fetchall()])) 
...  
>>> previous_ids 
'(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99)' 

編集:これは、長い文字列の使用を避けるaugenblickよりも時間がかかります。基本的にはテーブルを使って実装された考え方と同じです。

トリプレットインデックス作成
>>> import sqlite3 
>>> conn = sqlite3.connect('recur.db') 
>>> c = conn.cursor() 
>>> N_V = [ 
... (0, (0,6)), 
... (0, (0, 1)), 
... (1, (0, 2)), 
... (2, (0, 3)), 
... (0, (0, 5)), 
... (1, (0, 6)), 
... (2, (0, 7)), 
... (0, (0, 8)), 
... (1, (0, 9)), 
... (2, (1, 2)) 
... ] 
>>> r = c.execute('''CREATE TABLE essentials AS SELECT ID, N, V FROM the_table WHERE N=0 AND V BETWEEN 0 AND 6''') 
>>> for n_v in N_V[1:]: 
...  r = c.execute('''CREATE TABLE next AS SELECT * FROM essentials WHERE essentials.ID IN (SELECT ID FROM the_table WHERE N=%s AND V BETWEEN %s AND %s)''' % (n_v[0], n_v[1][0], n_v[1][1])) 
...  r = c.execute('''DROP TABLE essentials''') 
...  r = c.execute('''ALTER TABLE next RENAME TO essentials''') 
... 
+0

あなたの答えをありがとう、それは確かに良いアプローチです。このアプローチは大きなテーブルを扱うことができると思いますか? (1)数値リストを使用するとIN文の長さが制限されていると考えているため、(2)この方法は大量のデータを読み込み(少なくとも最初の繰り返しでは)、選択速度が遅くなります。 – user2660966

+0

数値リストの長さの制限の回避策は考えていません。あなたはそれについて正しいと確信しています。 「このアプローチは大量のデータをロードすることを意味します」とはどういう意味ですか? –

+0

私は、リスト "previous_ids"が最初のステップ(私の場合は数百万)で多くのアイテムを持っている可能性があり、fetchallコマンドに時間がかかることを意味します。 – user2660966

0

(ID、Nを、V)の代わりのみの(N、V)ダブレットは

create index I on TABLE(ID, N, V) 

、次いで

select ID from 
     (select ID from TABLE where N = 0 and V between ? and ?) 
    join (select ID from TABLE where N = 7 and V between ? and ?) using (ID) 
    join (select ID from TABLE where N = 8 and V between ? and ?) using (ID) 
    join ... 
見なされるために十分な速度加入アプローチを作っ