2012-02-04 16 views
6

के साथ 3-tuples शर्तों की सूची से मेल प्राप्त करने के लिए:कैसे पंक्तियों जो 3-tuples की एक सूची होने SQLAlchemy

[(a, b, c), (d, e, f)] 

मैं एक मेज जहां 3 कॉलम tuples से मेल खाता से सभी पंक्तियों को प्राप्त करना चाहते हैं। इस उदाहरण के लिए, क्वेरी WHERE खंड कुछ इस तरह हो सकता है:

(column_X = a AND column_Y = b AND column_Z = c) 
OR (column_X = d AND column_Y = e AND column_Z = f) 

मैं SQLAlchemy का उपयोग कर इस तरह का अनुरोध कैसे बना सकते हैं? मेरे मामले में 3-टुपल्स सूची में तत्वों के सौ शामिल होंगे, और मैं सबसे अच्छा स्केल करने योग्य समाधान ढूंढ रहा हूं।

आपकी मदद के लिए धन्यवाद,

उत्तर

8

सबसे आसान तरीका का उपयोग करेंगे SQLAlchemy-प्रदान की tuple_ समारोह:

from sqlalchemy import tuple_ 

session.query(Foo).filter(tuple_(Foo.a, Foo.b, Foo.c).in_(items)) 

यह PostgreSQL के साथ काम करता है, लेकिन SQLite के साथ टूट जाता है। अन्य डेटाबेस इंजनों के बारे में निश्चित नहीं है।

सौभाग्य से एक कामकाज है जो सभी डेटाबेस पर काम करना चाहिए।

प्रारंभ and_ अभिव्यक्ति के साथ सभी वस्तुओं मानचित्रण द्वारा:

:

q.filter(or_(*conditions)) 

यहाँ एक सरल उदाहरण है:

conditions = (and_(c1=x, c2=y, c3=z) for (x, y, z) in items) 

और फिर एक or_ फिल्टर है कि सभी शर्तों encloses बनाने

#/usr/bin/env python 
from sqlalchemy import create_engine 
from sqlalchemy import Column, Integer 
from sqlalchemy.sql import and_, or_ 
from sqlalchemy.orm import sessionmaker 
from sqlalchemy.ext.declarative import declarative_base 

engine = create_engine('sqlite:///') 
session = sessionmaker(bind=engine)() 
Base = declarative_base() 

class Foo(Base): 
    __tablename__ = 'foo' 

    id = Column(Integer, primary_key=True) 
    a = Column(Integer) 
    b = Column(Integer) 
    c = Column(Integer) 

    def __init__(self, a, b, c): 
     self.a = a 
     self.b = b 
     self.c = c 

    def __repr__(self): 
     return '(%d %d %d)' % (self.a, self.b, self.c) 

Base.metadata.create_all(engine) 

session.add_all([Foo(1, 2, 3), Foo(3, 2, 1), Foo(3, 3, 3), Foo(1, 3, 4)]) 
session.commit() 
items = ((1, 2, 3), (3, 3, 3)) 
conditions = (and_(Foo.a==x, Foo.b==y, Foo.c==z) for (x, y, z) in items) 
q = session.query(Foo) 
print q.all() 
q = q.filter(or_(*conditions)) 
print q 
print q.all() 

कौन सा आउटपुट:

$ python test.py 
[(1 2 3), (3 2 1), (3 3 3), (1 3 4)] 
SELECT foo.id AS foo_id, foo.a AS foo_a, foo.b AS foo_b, foo.c AS foo_c 
FROM foo 
WHERE foo.a = :a_1 AND foo.b = :b_1 AND foo.c = :c_1 OR foo.a = :a_2 AND foo.b = :b_2 AND foo.c = :c_2 
[(1 2 3), (3 3 3)] 
+0

बहुत बहुत धन्यवाद, यह सही है! –

2

एक कम पारंपरिक दृष्टिकोण है कि मैं अच्छी तरह से बड़े पैमाने होगा संदेह है अपने सभी tuples की एक अस्थायी तालिका बनाने के लिए किया जाएगा और फिर उस पर में शामिल होने:

import sqlalchemy 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy import Column, Integer, Table 
from sqlalchemy.orm import sessionmaker 
Base = declarative_base() 
engine = sqlalchemy.create_engine('sqlite:///:memory:') 
Session = sessionmaker(bind=engine) 
session = Session() 

class Triple(Base): 
    __tablename__ = 'triple' 
    id = Column(Integer(), primary_key=True) 
    x = Column(Integer()) 
    y = Column(Integer()) 
    z = Column(Integer()) 

ws_table = Table('where_sets', Base.metadata, 
     Column('x', Integer()), 
     Column('y', Integer()), 
     Column('z', Integer()), 
     prefixes = ['temporary'] 
    ) 

Base.metadata.create_all(engine) 

... 

where_sets = [(1, 2, 3), (3, 2, 1), (1, 1, 1)] 
ws_table.create(engine, checkfirst=True) 
session.execute(ws_table.insert(), [dict(zip('xyz', s)) for s in where_sets]) 
matches = session.query(Triple).join(ws_table, (Triple.x==ws_table.c.x) & (Triple.y==ws_table.c.y) & (Triple.z==ws_table.c.z)).all() 

जो इस तरह एसक्यूएल निष्पादित करता है:

INSERT INTO triple (x, y, z) VALUES (?, ?, ?) 
(1, 2, 3) 
INSERT INTO triple (x, y, z) VALUES (?, ?, ?) 
(3, 1, 2) 
INSERT INTO triple (x, y, z) VALUES (?, ?, ?) 
(1, 1, 1) 
SELECT triple.id AS triple_id, triple.x AS triple_x, triple.y AS triple_y, triple.z AS triple_z 
FROM triple JOIN where_sets ON triple.x = where_sets.x AND triple.y = where_sets.y AND triple.z = where_sets.z 
+0

मुझे लगता है कि यह समाधान पिछले एक की तुलना में बहुत धीमा हो सकता है जो आपको नहीं लगता? वैसे भी, उदाहरण के लिए धन्यवाद :-) –

+0

@Thibaut: जब तक आप इसे आज तक नहीं जानते, तब तक नहीं पता! मुझे पता है कि मैंने बड़े पैमाने पर "इन" खंडों के साथ काम पर अपने घुटनों पर उच्च पैमाने पर उत्पादन प्रणाली लाई है, और मुझे नहीं पता कि विशाल "कहां" खंड सिद्धांत में बेहतर होंगे। लेकिन आप बहुत से इंसर्ट्स को जानते हैं और एक छोटी सी जॉइन ठीक रहेगी। चूंकि आपने विशेष रूप से "सर्वश्रेष्ठ स्केलेबल समाधान" के लिए पूछा है, जो मैंने सोचा था, लेकिन शायद कुछ सौ पर्याप्त नहीं है कि इससे कोई फर्क नहीं पड़ता। किसी भी दर पर, अगर आपको इसकी ज़रूरत है तो यह वहां है। –

संबंधित मुद्दे