SQLAlchemy WHERE IN single value (raw SQL)

后端 未结 1 958
独厮守ぢ
独厮守ぢ 2021-01-19 21:13

I\'m having trouble with SQLAlchemy when doing a raw SQL which checks against multiple values.

my_sess.execute(
        \"SELECT * FROM table WHERE `key`=\'r         


        
相关标签:
1条回答
  • 2021-01-19 21:42

    No, SQL parameters only ever deal with scalar values. You'll have to generate the SQL here; if you need raw SQL, use:

    statement = "SELECT * FROM table WHERE `key`='rating' AND uid IN ({})".format(
        ', '.join([':i{}'.format(i) for i in range(len(some_list))]))
    
    my_sess.execute(
            statement, 
            params={'i{}'.format(i): v for i, v in enumerate(some_list)})
        ).fetchall()
    

    e.g. generate enough parameters to hold all values in some_list with string formatting, then generate matching parameters to fill them.

    Better still would be to use a literal_column() object to do all the generating for you:

    from sqlalchemy.sql import literal_column
    
    uid_in = literal_column('uid').in_(some_list)
    statement = "SELECT * FROM able WHERE `key`='rating' AND {}".format(uid_in)
    
    my_sess.execute(
            statement, 
            params={'uid_{}'.format(i): v for i, v in enumerate(some_list)})
        ).fetchall()
    

    but then you perhaps could just generate the whole statement using the `sqlalchemy.sql.expression module, as this would make supporting multiple database dialects much easier.

    Moreover, the uid_in object already holds references to the right values for the bind parameters; instead of turning it into a string as we do with the str.format() action above, SQLAlchemy would have the actual object plus the associated parameters and you would no longer have to generate the params dictionary either.

    The following should work:

    from sqlalchemy.sql import table, literal_column, select
    
    tbl = table('table')
    key_clause = literal_column('key') == 'rating'
    uid_clause = literal_column('uid').in_(some_list)
    my_sess.execute(select('*', key_clause & uid_clause, [tbl]))
    

    where the sqlalchemy.sql.select() takes a column spec (here hard-coded to *), a where clause (generated from the two clauses with & to generate a SQL AND clause) and a list of selectables; here your one sqlalchemy.sql.table() value.

    Quick demo:

    >>> from sqlalchemy.sql import table, literal_column, select
    >>> some_list = ['foo', 'bar']
    >>> tbl = table('table')
    >>> key_clause = literal_column('key') == 'rating'
    >>> uid_clause = literal_column('uid').in_(some_list)
    >>> print select('*', key_clause & uid_clause, [tbl])
    SELECT * 
    FROM "table" 
    WHERE key = :key_1 AND uid IN (:uid_1, :uid_2)
    

    but the actual object tree generated from all this contains the actual values for the bind parameters too, so my_sess.execute() can access these directly.

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