Як використовувати змінні в операторі SQL у Python?


91

Гаразд, я не такий досвідчений у Python.

У мене є такий код Python:

cursor.execute("INSERT INTO table VALUES var1, var2, var3,")

де var1- ціле число, var2& - var3це рядки.

Як я можу писати імена змінних без python, включаючи їх як частину тексту запиту?

Відповіді:


103
cursor.execute("INSERT INTO table VALUES (%s, %s, %s)", (var1, var2, var3))

Зверніть увагу, що параметри передаються як кортеж.

API бази даних робить правильне екранування та цитування змінних. Будьте обережні, щоб не використовувати оператор форматування рядків ( %), оскільки

  1. він не робить жодного втечі або цитування.
  2. він схильний до неконтрольованих атак формату рядка, наприклад, введення SQL .

Цікаво, чому він працює з vars окремо, а не в масиві (var1, var2, var3)?
Andomar

Відповідно до специфікацій API DB, схоже, це може бути в будь-якому випадку: python.org/dev/peps/pep-0249
Айман Хоурі,

9
@thekashyap Прочитайте ще раз уважно. Невпевненим є використання оператора форматування рядків %. Насправді я так кажу у відповіді.
Айман Хоурі

мій поганий .. Я уявив собі % замість того, ,щоб між рядком і змінними .. не можу скасувати моє зменшення голосу через різні причини .. Я особисто хотів би, щоб у описі були згадані такі слова, як небезпечний / атака тощо не %
вживаю

1
Відповідь @eric говорить: не використовуйте % оператор для форматування рядка. Ті, хто входить %до рядка, використовуються cursor.executeбезпосередньо, і оскільки він знає, що він генерує SQL, він може зробити більше, щоб захистити вас.
Марк Ренсом

66

Різні реалізації Python DB-API дозволяють використовувати різні заповнювачі, тому вам потрібно буде з’ясувати, який саме ви використовуєте - це може бути (наприклад, з MySQLdb):

cursor.execute("INSERT INTO table VALUES (%s, %s, %s)", (var1, var2, var3))

або (наприклад, з sqlite3 зі стандартної бібліотеки Python):

cursor.execute("INSERT INTO table VALUES (?, ?, ?)", (var1, var2, var3))

або інші ще (після VALUESтого, як ви могли мати (:1, :2, :3), або "названі стилі", (:fee, :fie, :fo)або (%(fee)s, %(fie)s, %(fo)s)де ви передаєте дикт замість карти як другий аргумент execute). Перевірте paramstyleконстанту рядка в модулі DB API, який ви використовуєте, і знайдіть парамстиль на http://www.python.org/dev/peps/pep-0249/, щоб побачити, якими є всі стилі передавання параметрів!


Можна зробити те саме, але із зовнішнім сценарієм SQL?
Novitoll

46

Багато шляхів. НЕ використовуйте найбільш очевидний ( %sз %) у реальному коді, він відкритий для атак .

Ось скопіюйте-вставіть із pydoc з sqlite3 :

# Never do this -- insecure!
symbol = 'RHAT'
c.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol)

# Do this instead
t = ('RHAT',)
c.execute('SELECT * FROM stocks WHERE symbol=?', t)
print c.fetchone()

# Larger example that inserts many records at a time
purchases = [('2006-03-28', 'BUY', 'IBM', 1000, 45.00),
             ('2006-04-05', 'BUY', 'MSFT', 1000, 72.00),
             ('2006-04-06', 'SELL', 'IBM', 500, 53.00),
            ]
c.executemany('INSERT INTO stocks VALUES (?,?,?,?,?)', purchases)

Інші приклади, якщо вам потрібно:

# Multiple values single statement/execution
c.execute('SELECT * FROM stocks WHERE symbol=? OR symbol=?', ('RHAT', 'MSO'))
print c.fetchall()
c.execute('SELECT * FROM stocks WHERE symbol IN (?, ?)', ('RHAT', 'MSO'))
print c.fetchall()
# This also works, though ones above are better as a habit as it's inline with syntax of executemany().. but your choice.
c.execute('SELECT * FROM stocks WHERE symbol=? OR symbol=?', 'RHAT', 'MSO')
print c.fetchall()
# Insert a single item
c.execute('INSERT INTO stocks VALUES (?,?,?,?,?)', ('2006-03-28', 'BUY', 'IBM', 1000, 45.00))

4
Деякі реалізації DB-API насправді використовують% s для своїх змінних - перш за все psycopg2 для PostgreSQL. Це не слід плутати (хоча це легко) із використанням% s з оператором% для заміни рядків. Мені було б дуже добре, якби для портативності ми могли просто мати визначений стандартний спосіб визначення параметрів SQL для DB-API.
ThatAintWorking

24

http://www.amk.ca/python/writing/DB-API.html

Будьте обережні, коли просто додаєте значення змінних до своїх висловлювань: Уявіть, що користувач називає себе ';DROP TABLE Users;'- Ось чому вам потрібно використовувати екранування sql, яке Python надає вам, коли ви гідно використовуєте cursor.execute. Приклад в URL-адресі:

cursor.execute("insert into Attendees values (?, ?, ?)", (name,
seminar, paid) )

13
Насправді це не SQL-захист. Це прив’язка змінних, яка набагато простіша і пряміша. Ці значення прив'язуються до оператора SQL після аналізу, що робить його несприйнятливим до будь-якої ін'єкційної атаки.
С.Лотт,

добре, чи буде це екранування SQL чи прив'язка змінних, залежить від того, наскільки хорошим чи поганим є ваш сервер баз даних / драйвер DB-API. Я бачив деякі реальні, широко розгорнуті виробничі бази даних, у яких драйвер DB-API просто робить екранування, а не зберігає дані та код поза діапазоном на дроті. Що й казати, я не дуже поважаю ці так звані "бази даних".
Чарльз Даффі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.