2013-12-09 18 views
7

SQLAlchemyを使用して複数の列をクエリに書く方法はありますか?ここでsqlalchemyで複数の列を記述する方法

は、実際のクエリの例です:

SELECT url FROM pages WHERE (url_crc, url) IN ((2752937066, 'http://members.aye.net/~gharris/blog/'), (3799762538, 'http://www.coxandforkum.com/')); 

私は2つの列の主キーを持つテーブルを持っていると私はちょうど指標として使用する1つの以上のキーを追加することを避けるために願っています。

PS私はmysql DBを使用しています。

更新:このクエリはバッチ処理に使用されるので、私は数百ペアをin節に入れる必要があります。 IN句のアプローチでは、1つのクエリにどれくらいの数のペアを張ることができるかという固定の制限を知りたいと思っています。 Oracleのように、デフォルトで1000の列挙制限があります。

AND/ORの組み合わせを使用すると、クエリの長​​さが文字数で制限されることがあります。それは可変であまり予測できません。

答えて

0

が、私はテスト()ベースのソリューションを使用して終了:生成された「(a、b)は((で:A1:B1)、(:A2 、:b2)、...) "を指定し、バインド変数の値を持つ辞書を生成します。

params = {} 
for counter, r in enumerate(records): 
    a_param = "a%s" % counter 
    params[a_param] = r['a'] 
    b_param = "b%s" % counter 
    params[b_param] = r['b'] 
    pair_text = "(:%s,:%s)" % (a_param, b_param) 
    enum_pairs.append(pair_text) 
multicol_in_enumeration = ','.join(enum_pairs) 
multicol_in_clause = text(
    " (a,b) in (" + multicol_in_enumeration + ")") 
q = session.query(Table.id, Table.a, 
          Table.b).filter(multicol_in_clause).params(params) 

私はMySQLのアップサートを使用して考えたが、これは全体の句で複数列を使用して、その後さらに少ないポータブル他のDBエンジンのための付属なるだろう別のオプション。

更新 SQLAlchemyには、同じ目的で使用できるsqlalchemy.sql.expression.tuple_(*clauses, **kw)構造があります。あなたのモデルがPageで定義されていると仮定すると

1

現在、sqlalchemyではこれが可能ではないと考えていますが、すべてのRDMBSがこれをサポートしているわけではありません。
あなたはいつもしかしOR(AND...)条件にこれを変換することができます。

filter_rows = [ 
    (2752937066, 'http://members.aye.net/~gharris/blog/'), 
    (3799762538, 'http://www.coxandforkum.com/'), 
    ] 
qry = session.query(Page) 
qry = qry.filter(or_(*(and_(Page.url_crc == crc, Page.url == url) for crc, url in filter_rows))) 
print qry 

は(SQLiteのため)のようなものを作る必要があります。

SELECT pages.id AS pages_id, pages.url_crc AS pages_url_crc, pages.url AS pages_url 
FROM pages 
WHERE pages.url_crc = ? AND pages.url = ? OR pages.url_crc = ? AND pages.url = ? 
-- (2752937066L, 'http://members.aye.net/~gharris/blog/', 3799762538L, 'http://www.coxandforkum.com/') 

また、あなただけの1に2つの列を組み合わせることができます。

filter_rows = [ 
    (2752937066, 'http://members.aye.net/~gharris/blog/'), 
    (3799762538, 'http://www.coxandforkum.com/'), 
    ] 
qry = session.query(Page) 
qry = qry.filter((func.cast(Page.url_crc, String) + '|' + Page.url).in_(["{}|{}".format(*_frow) for _frow in filter_rows])) 
print qry 

下記(SQLiteのために)、あなたはINを使用できるように:

SELECT pages.id AS pages_id, pages.url_crc AS pages_url_crc, pages.url AS pages_url 
FROM pages 
WHERE (CAST(pages.url_crc AS VARCHAR) || ? || pages.url) IN (?, ?) 
-- ('|', '2752937066|http://members.aye.net/~gharris/blog/', '3799762538|http://www.coxandforkum.com/') 
+0

それは、実行可能なアイデアです。しかし、私の必要性に合っていません。私はより詳細な質問を延長しました。 – vvladymyrov

+0

「IN」バージョンnでの回答も更新されました。 – van

+0

ありがとうございました。私は2つの列を1つの文字列に結合することを考えました - しかし、この場合はインデックスが使用されないので、これは遅くなります。 – vvladymyrov

7

を(私はまだそれを試していない)、ここでtuple_を使用した例です:

keys = [ 
    (2752937066, 'http://members.aye.net/~gharris/blog/'), 
    (3799762538, 'http://www.coxandforkum.com/') 
] 

select([ 
    Page.url 
]).select_from(
    Page 
).where(
    tuple_(Page.url_crc, Page.url).in_(keys) 
) 

または、クエリAPIを使用して:

session.query(Page.url).filter(tuple_(Page.url_crc, Page.url).in_(keys)) 
関連する問題