2009-06-04 18 views
6

Estoy tratando de encontrar una manera de hacer que sqlalchemy para generar SQL de la siguiente forma:sqlalchemy cláusula in_ complejo

 
select * from t where (a,b) in ((a1,b1),(a2,b2)); 

Es esto posible?

Si no, ¿alguna sugerencia sobre cómo emularlo?

Gracias amablemente!

Respuesta

3

Bueno, gracias a Hao Lian anterior, se me ocurrió una solución funcional aunque dolorosa.

Supongamos que tenemos un estilo declarativo clase mapeada, Clazz, y una list de tuplas de valores de clave principal compuesto, values (Editado para utilizar una (OMI) sql estilo mejor generación):

 
from sqlalchemy.sql.expression import text,bindparam 
... 
    def __gParams(self, f, vs, ts, bs): 
     for j,v in enumerate(vs): 
      key = f % (j+97) 
      bs.append(bindparam(key, value=v, type_=ts[j])) 
      yield ':%s' % key 

    def __gRows(self, ts, values, bs): 
     for i,vs in enumerate(values): 
      f = '%%c%d' % i 
      yield '(%s)' % ', '.join(self.__gParams(f, vs, ts, bs)) 

    def __gKeys(self, k, ts): 
     for c in k: 
      ts.append(c.type) 
      yield str(c) 

    def __makeSql(self,Clazz, values): 
     t = [] 
     b = [] 
     return text(
       '(%s) in (%s)' % (
        ', '.join(self.__gKeys(Clazz.__table__.primary_key,t)), 
        ', '.join(self.__gRows(t,values,b))), 
       bindparams=b) 

Esta solución funciona para claves primarias compuestas o simples. Sin embargo, es ligeramente más lento que el col.in_(keys) para claves primarias simples.

Todavía estoy interesado en sugerencias de mejores formas de hacerlo, pero de esta manera está funcionando por ahora y funciona notablemente mejor que la forma or_(and_(conditions)), o la forma for key in keys: do_stuff(q.get(key)).

4

Advertencia: No soy experto en el ecosistema grande y revuelto que es SQLAlchemy.

Digamos que tiene una tabla llamada stocks y una sesión llamada session. A continuación, la consulta sólo sería algo así como

x = "(stocks.person, stocks.number) IN ((100, 100), (200, 200))" 
session.query(stocks).filter(x).all() 

Una buena regla general es que SQLAlchemy aceptará SQL prima en la mayoría de los lugares en los que parece que podría ser generada, como el método filter.

Sin embargo, no creo que haya una manera de hacerlo sin SQL sin formato. El operador in_ parece estar definido solo en Column s en lugar de tuplas de columnas como las que tiene en su ejemplo. (Además, esto solo funciona en implementaciones de SQL que lo soportan, SQLite, en particular, parece no ser compatible con esto en los ejemplos rápidos que ejecuté. También debe tener cuidado al calificar las columnas en la tupla izquierda, especialmente si SQLAlchemy manejó amablemente el creación de tablas.)

+0

tenía miedo de que - que sería una construcción muy útil cuando se trata de claves primarias compuestas. ¡Gracias por la respuesta! – lostlogic

17

Uso tuple_:

keys = [(a1, b1), (a2, b2)] 
session.query(T).filter(tuple_(T.a, T.b).in_(keys)).all() 

http://docs.sqlalchemy.org/en/latest/core/sqlelement.html#sqlalchemy.sql.expression.tuple_

+0

Advertencia Advertencia (de sqlalchemy doc): la construcción compuesta de IN no es compatible con todos los backends, y actualmente se sabe que funciona en PostgreSQL y MySQL, pero no SQLite. Los backends no soportados generarán una subclase de DBAPIError cuando se invoque dicha expresión. – Bryan