В моем коде Python я часто выполняю следующее (используя DB-API):
yValues = pickInterestingValuesOfY()
sql = "..." # includes a clause stating that "y must be in yValues"
c.execute(sql, yValues)
В конце концов, выполняемый SQL может быть таким простым, как
SELECT x FROM table1 WHERE y IN (1,2,3);
Проблема в том, что набор возможных значений для y (1,2,3) определяется во время выполнения.
У меня есть две проблемы:
- генерирует допустимый SQL в случае, если yValues пуст («WHERE y IN ()» является недействительным SQL)
- следить за внедрением sql, если значения получены из ненадежного источника
Для решения (2) я должен позволить DB-API фактически вставить значения yValues в оператор SQL. Поэтому я получил следующее запутанное решение:
def inClause(columnName, values):
if len(values):
placeHolders = ','.join( ['%s'] * len(values) )
sql = "%s IN (%s)" % (columnName, placeHolders)
else:
sql = "FALSE"
return "(%s)" % sql
# get a db-api cursor called c
c.execute("SELECT x FROM table1 WHERE %s;" % inClause('y', yValues), yValues)
, который, кажется, правильно решает обе проблемы выше. Однако я не могу поверить, что это неуклюжее решение - то, что нужно.
Как вы обрабатываете такие запросы? Мне не хватает более элегантного способа сделать это?
Я не ищу ORM.
(Я использую MySQL, поэтому, если есть какой-то магический нестандартный переключатель mysql, который молча принимает WHERE y IN () 'как действительный, просто дайте мне знать, и о проблеме (1) позаботятся.)