SQLAlchemy ГДЕ В одном значении (raw SQL)

У меня возникают проблемы с SQLAlchemy при выполнении необработанного SQL, который проверяет несколько значений.

my_sess.execute( "SELECT * FROM table WHERE `key`='rating' AND uid IN :uids", params=dict(uids=some_list) ).fetchall() 

Для этого запроса есть 2 сценария, один из которых работает, а другой – нет. Если some_list = [1] , это вызывает ошибку SQL, у меня есть синтаксическая ошибка ) . Но если some_list = [1, 2] , запрос выполняется успешно.

Любая причина, почему это произойдет?

Нет, параметры SQL всегда имеют дело со скалярными значениями. Вы должны будете генерировать SQL здесь; если вам нужен сырой SQL, используйте:

 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() 

например, генерировать достаточно параметров для хранения всех значений в some_list с форматированием строки, а затем создавать соответствующие параметры для их заполнения.

Лучше всего было бы использовать объект literal_column() чтобы сделать все генерирование для вас:

 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() 

но тогда вы, возможно, могли бы просто сгенерировать весь оператор, используя модуль sqlalchemy.sql.expression, поскольку это облегчило бы поддержку множества диалектов базы данных.

Кроме того, объект uid_in уже содержит ссылки на правильные значения для параметров привязки; вместо того, чтобы превращать его в строку, как в случае действия str.format() выше, SQLAlchemy будет иметь фактический объект плюс связанные параметры, и вам больше не придется генерировать словарь params .

Следующее должно работать:

 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])) 

где sqlalchemy.sql.select() принимает спецификацию столбца (здесь жестко закодирована до * ), предложение where (генерируемое из двух предложений с помощью & для создания предложения SQL AND ) и список выборочных; здесь ваше одно значение sqlalchemy.sql.table() .

Быстрая демонстрация:

 >>> 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) 

но фактическое дерево объектов, генерируемое из всего этого, также содержит фактические значения для параметров связывания, поэтому my_sess.execute() может обращаться к ним напрямую.