Cómo escribir múltiples columnas en la cláusula con sqlalchemy

Por favor, sugiera ¿hay alguna manera de escribir consultas de varias columnas en la cláusula usando SQLAlchemy?

Aquí está el ejemplo de la consulta real:

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

Tengo una tabla que tiene dos columnas de clave principal y espero evitar agregar una clave más solo para usarla como índice.

PS Estoy usando mysql DB.

Actualización: esta consulta se utilizará para el procesamiento por lotes, por lo que necesitaría poner unos cientos de pares en la cláusula in. Con el enfoque de la cláusula IN espero saber el límite fijo de cuántos pares puedo mantener en una consulta. Al igual que Oracle, tiene 1000 enumeración límite por defecto.

El uso de la combinación Y / O puede estar limitado por la longitud de la consulta en caracteres. Lo cual sería variable y menos predecible.

Suponiendo que tienes tu modelo definido en Page , aquí hay un ejemplo usando 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) ) 

O, usando la API de consulta:

 session.query(Page.url).filter(tuple_(Page.url_crc, Page.url).in_(keys)) 

No creo que esto sea actualmente posible en sqlalchemy, y no todos los RDMBS son compatibles con esto.
Aunque siempre puedes transformar esto en una condición 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 

Debe producir algo como (para 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/') 

Alternativamente , puedes combinar dos columnas en una sola:

 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 

que produce lo siguiente (para SQLite), por lo que puede usar 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/') 

Terminé usando la solución basada en test (): generé “(a, b) en ((: a1,: b1), (: a2,: b2), …)” con vars vinculados con nombre y generando un diccionario con bind Los valores de vars.

 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) 

Otra opción que pensé en usar las actualizaciones de mysql, pero esto haría que todo fuera incluso menos portátil para el otro motor de db y luego usar una columna de varias columnas en.

La actualización SQLAlchemy tiene una construcción sqlalchemy.sql.expression.tuple _ (* cláusulas, ** kw) que se puede usar para el mismo propósito. (No lo he probado todavía)