#python #sql #oracle #cx-oracle
#python #sql #Oracle #cx-oracle
Вопрос:
Я пытаюсь запустить операторы SQL через Python в списке. Путем передачи списка, в данном случае даты. Поскольку я хочу запустить несколько запросов SELECT SQL и вернуть их. Я проверил это, передав целые числа, однако при попытке передать дату я получаю ошибку ORA-01036. Недопустимое имя / номер переменной. Я использую Oracle DB.
cursor = connection.cursor()
date = ["'01-DEC-21'", "'02-DEC-21'"]
sql = "select * from table1 where datestamp = :date"
for item in date:
cursor.execute(sql,id=item)
res=cursor.fetchall()
print(res)
Есть предложения по выполнению этого запуска?
Комментарии:
1. используйте IN вместо =, = для одного значения, а IN — для списка
2. @AhmedSunny спасибо за эту информацию. Это большая таблица, и иногда для ее анализа требуется больше времени, чем для выполнения по одному за раз
3. Прочитайте документацию cx_Oracle, связывающую несколько значений с предложением SQL WHERE IN , в котором есть некоторые общие решения.
Ответ №1:
Вы не можете назвать переменную привязки date
, это недопустимое имя. Также ваша именованная переменная в cursor.execute
должна соответствовать имени переменной привязки. Попробуйте что-то вроде:
sql = "select * from table1 where datestamp = :date_input"
for item in date:
cursor.execute(sql,date_input=item)
res=cursor.fetchall()
print(res)
Ответ №2:
Некоторые рекомендации и предупреждения для вашего подхода:
- вы не должны зависеть от настройки
NLS
даты по умолчанию при привязке aString
(например"'01-DEC-21'"
) кDATE
столбцу. (Вероятно, вам также нужно изменить одну из кавычек). - Вы должны отказаться от извлечения данных в цикле, если вы можете получить их в одном запросе (используя
IN
список) - используйте подготовленный оператор
Пример
date = ['01-DEC-21', '02-DEC-21']
Это генерирует запрос, который использует переменные привязки для вашего входного списка
in_list = ','.join([f" TO_DATE(:d{ind},'DD-MON-RR','NLS_DATE_LANGUAGE = American')" for ind, d in enumerate(date)])
sql_query = "select * from table1 where datestamp in ( " in_list " )"
sql_query
Генерируется
select * from table1 where datestamp in
( TO_DATE(:d0,'DD-MON-RR','NLS_DATE_LANGUAGE = American'), TO_DATE(:d1,'DD-MON-RR','NLS_DATE_LANGUAGE = American') )
Обратите внимание, что IN
список содержит одну переменную привязки для каждого элемента вашего списка ввода.
Обратите также внимание на использование to_date
с явной маской и исправление языка, чтобы избежать проблем с интерпретацией сокращения месяца. (например ORA-01843: not a valid month
)
Теперь вы можете использовать запрос для извлечения данных за один проход
cur.prepare(sql_query)
cur.execute(None, date)
res = cur.fetchall()
Комментарии:
1. Спасибо за этот ввод. Я изменил, и теперь я получаю
cx_Oracle.DatabaseError: ORA-01830: date format picture ends before converting entire input string
2. Поскольку Oracle имеет кэш инструкций , может быть мало пользы от явного
prepare()
3. Это верно, а также кэш курсора работает нормально @ChristopherJones. Итак, в этом простом примере видимого эффекта не будет. В любом случае, рекомендация IMO использовать подготовленные операторы в крупномасштабных приложениях остается в силе.