How to write multi column in clause with sqlalchemy

前端 未结 3 1133
时光取名叫无心
时光取名叫无心 2020-12-16 03:57

Please suggest is there way to write query multi-column in clause using SQLAlchemy?

Here is example of the actual query:

SELECT  url FROM pages WHERE         


        
相关标签:
3条回答
  • 2020-12-16 03:58

    Assuming that you have your model defined in Page, here's an example using 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)
    )
    

    Or, using the query API:

    session.query(Page.url).filter(tuple_(Page.url_crc, Page.url).in_(keys))
    
    0 讨论(0)
  • 2020-12-16 04:13

    I do not think this is currently possible in sqlalchemy, and not all RDMBS support this.
    You can always transform this to a OR(AND...) condition though:

    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
    

    should produce something like (for 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/')
    

    Alternatively, you can combine two columns into just one:

    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
    

    which produces the below (for SQLite), so you can use 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 讨论(0)
  • 2020-12-16 04:24

    I ended up using the test() based solution: generated "(a,b) in ((:a1, :b1), (:a2,:b2), ...)" with named bind vars and generating dictionary with bind vars' values.

    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)
    

    Another option I thought about using mysql upserts but this would make whole included even less portable for the other db engine then using multicolumn in clause.

    Update SQLAlchemy has sqlalchemy.sql.expression.tuple_(*clauses, **kw) construct that can be used for the same purpose. (I haven't tried it yet)

    0 讨论(0)
提交回复
热议问题