Bagaimana cara menggunakan variabel dalam pernyataan SQL dengan Python?

94

Ok jadi saya tidak begitu berpengalaman dengan Python.

Saya memiliki kode Python berikut:

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

Dimana var1adalah integer, var2& var3adalah string.

Bagaimana saya bisa menulis nama variabel tanpa python memasukkannya sebagai bagian dari teks kueri?

pengguna111606
sumber

Jawaban:

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

Perhatikan bahwa parameter dikirimkan sebagai tupel.

API database melakukan pelolosan dan kutipan variabel dengan benar. Berhati-hatilah untuk tidak menggunakan operator pemformatan string ( %), karena

  1. ia tidak melakukan pelolosan atau kutipan.
  2. itu rentan terhadap serangan format string yang tidak terkontrol misalnya injeksi SQL .
Ayman Hourieh
sumber
Menarik, mengapa ini bekerja dengan vars secara terpisah dan bukan dalam array (var1, var2, var3)?
Andomar
Menurut spesifikasi DB API, sepertinya itu bisa terjadi: python.org/dev/peps/pep-0249
Ayman Hourieh
9
@thekashyap Baca lagi dengan seksama. Apa yang tidak aman menggunakan operator pemformatan string %. Nyatanya, saya katakan demikian dalam jawabannya.
Ayman Hourieh
saya buruk .. Saya membayangkan % alih- ,alih antara string dan variabel .. tidak dapat membatalkan suara saya karena berbagai alasan .. Saya pribadi ingin melihat kata-kata seperti tidak aman / serangan dll disebutkan dalam deskripsi di mana Anda mengatakan jangan tidak digunakan %..
Kashyap
1
@eric jawabannya mengatakan jangan gunakan % operator untuk memformat string. Mereka yang ada %dalam string digunakan cursor.executesecara langsung, dan karena ia tahu itu menghasilkan SQL, ia dapat berbuat lebih banyak untuk melindungi Anda.
Mark Ransom
69

Implementasi berbeda dari Python DB-API diizinkan untuk menggunakan placeholder yang berbeda, jadi Anda harus mencari tahu mana yang Anda gunakan - bisa juga (misalnya dengan MySQLdb):

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

atau (misalnya dengan sqlite3 dari pustaka standar Python):

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

atau yang lain (setelah VALUESAnda bisa memiliki (:1, :2, :3), atau "gaya bernama" (:fee, :fie, :fo)atau di (%(fee)s, %(fie)s, %(fo)s)mana Anda meneruskan dict alih-alih peta sebagai argumen kedua ke execute). Periksa paramstylekonstanta string dalam modul DB API yang Anda gunakan, dan cari paramstyle di http://www.python.org/dev/peps/pep-0249/ untuk melihat apa saja gaya parameter-passing itu!

Alex Martelli
sumber
Apakah mungkin untuk melakukan hal yang sama tetapi dengan skrip SQL eksternal?
Novitoll
49

Banyak jalan. JANGAN gunakan yang paling jelas ( %sdengan %) dalam kode nyata, itu terbuka untuk serangan .

Di sini salin-tempel dari pydoc dari 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)

Lebih banyak contoh jika Anda membutuhkan:

# 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))
Kashyap
sumber
4
Beberapa implementasi DB-API sebenarnya menggunakan% s untuk variabel mereka - terutama psycopg2 untuk PostgreSQL. Hal ini tidak menjadi bingung (meskipun mudah) dengan menggunakan% s dengan operator% untuk penggantian string. Saya akan sangat baik jika, untuk portabilitas, kita bisa saja memiliki cara standar yang ditentukan untuk menentukan parameter SQL untuk DB-API.
ThatAintWorking
26

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

Berhati-hatilah saat Anda menambahkan nilai variabel ke pernyataan Anda: Bayangkan pengguna menamai dirinya sendiri ';DROP TABLE Users;'- Itulah mengapa Anda perlu menggunakan sql escaping, yang disediakan Python untuk Anda saat Anda menggunakan cursor.execute dengan cara yang layak. Contoh di url adalah:

cursor.execute("insert into Attendees values (?, ?, ?)", (name,
seminar, paid) )
Numlock
sumber
13
Sebenarnya, ini bukan SQL escaping. Ini mengikat variabel, yang jauh lebih sederhana dan lebih langsung. Nilai terikat ke dalam pernyataan SQL setelah parsing, membuatnya kebal terhadap serangan injeksi apa pun.
S. Lott
baik, apakah itu SQL escaping atau variable binding tergantung pada seberapa baik atau buruk server database / driver DB-API Anda. Saya telah melihat beberapa database produksi dunia nyata dan tersebar luas yang memiliki driver DB-API mereka yang melarikan diri, daripada menyimpan data dan kode di luar jalur kabel. Tak perlu dikatakan, saya tidak terlalu menghormati yang disebut "database".
Charles Duffy