Python'da SQL ifadesinde değişkenler nasıl kullanılır?


96

Tamam, Python'da o kadar deneyimli değilim.

Aşağıdaki Python koduna sahibim:

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

nerede var1bir tamsayı var2ve var3dizelerdir.

Değişken adlarını python olmadan sorgu metninin bir parçası olarak nasıl yazabilirim?

Yanıtlar:


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

Parametrelerin bir demet olarak aktarıldığını unutmayın.

Veritabanı API'si değişkenlerden uygun şekilde çıkış ve alıntı yapar. Dize formatlama operatörünü ( %) kullanmamaya dikkat edin , çünkü

  1. herhangi bir kaçış veya alıntı yapmaz.
  2. Kontrolsüz dizgi biçimi saldırılarına, örneğin SQL enjeksiyonuna eğilimlidir .

İlginç, neden bir dizi (var1, var2, var3) yerine değişkenlerle ayrı ayrı çalışıyor?
Andomar

DB API özelliklerine göre, her iki şekilde de olabilir gibi görünüyor: python.org/dev/peps/pep-0249
Ayman Hourieh

9
@thekashyap Tekrar dikkatlice okuyunuz. Güvensiz olan şey, dize biçimlendirme operatörünü kullanmaktır %. Aslında cevapta öyle söylüyorum.
Ayman Hourieh

benim hatam .. Dize ve değişkenler % yerine a hayal ettim ,.. çeşitli nedenlerden dolayı oyumu geri alamıyorum .. Ben şahsen güvensiz / saldırı gibi sözler görmek istiyorum. 't use %..
Kashyap

1
@eric yanıt , dizeyi biçimlendirmek için % operatörü kullanma der . Dizede olanlar doğrudan %tarafından kullanılıyor cursor.executeve SQL oluşturduğunu bildiği için sizi korumak için daha fazlasını yapabilir.
Mark Ransom

69

Python DB-API'nin farklı uygulamalarının farklı yer tutucular kullanmasına izin verilir, bu nedenle hangisini kullandığınızı bulmanız gerekir - bu olabilir (örneğin MySQLdb ile):

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

veya (örneğin Python standart kitaplığından sqlite3 ile):

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

veya diğerleri henüz ( VALUESsahip olabileceğiniz (:1, :2, :3)veya "adlandırılmış stiller" den sonra (:fee, :fie, :fo)veya (%(fee)s, %(fie)s, %(fo)s)ikinci argüman olarak bir harita yerine bir dikteyi aktardığınız yer execute). paramstyleKullanmakta olduğunuz DB API modülündeki dize sabitini kontrol edin ve tüm parametre geçiren stillerin ne olduğunu görmek için http://www.python.org/dev/peps/pep-0249/ adresinde paramstyle arayın !


Aynı şeyi harici SQL betiği ile yapmak mümkün mü?
Novitoll

50

Çok şekilde. En bariz olanı ( ile ) gerçek kodda KULLANMAYIN , saldırılara açıktır .%s%

İşte kopyalayıp paste'd sqlite3 ait pydoc gelen :

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

İhtiyacınız olursa daha fazla örnek:

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

5
Bazı DB-API uygulamaları değişkenleri için aslında% s kullanır - en önemlisi PostgreSQL için psycopg2. Bu, dizge değişimi için% s ile% işlecini kullanmakla karıştırılmamalıdır (kolay olsa da). Taşınabilirlik için, DB-API için SQL parametrelerini belirlemenin tanımlı bir standart yoluna sahip olsaydık gerçekten iyi olurdu.
ThatAintWorking

26

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

Değişkenlerin değerlerini basitçe ifadelerinize eklerken dikkatli olun: Kendini adlandıran bir kullanıcı hayal edin ';DROP TABLE Users;'- Bu nedenle, cursor.execute komutunu düzgün bir şekilde kullandığınızda Python'un size sağladığı sql escaping'i kullanmanız gerekir. URL'deki örnek:

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

13
Aslında SQL kaçışı değildir. Çok daha basit ve daha doğrudan olan değişken bağlamadır. Değerler, ayrıştırıldıktan sonra SQL ifadesine bağlanır ve bu da onu herhangi bir enjeksiyon saldırısına karşı bağışık hale getirir.
S.Lott

Peki, SQL kaçışının mı yoksa değişken bağlamanın mı olduğu, veritabanı sunucunuzun / DB-API sürücünüzün ne kadar iyi veya kötü olduğuna bağlıdır. Veri ve kodu bant dışında tutmak yerine, DB-API sürücüsüne sahip, gerçek dünyada yaygın olarak kullanılan bazı üretim veritabanları gördüm. Söylemeye gerek yok, bu sözde "veritabanları" na pek saygım yok.
Charles Duffy

0

Tek bir değer sağlamak için sözdizimi, deneyimsiz Python kullanıcıları için kafa karıştırıcı olabilir.

Sorgu göz önüne alındığında

INSERT INTO mytable (fruit) VALUES (%s)

İletilen değerin cursor.executemutlaka hala olmak tanımlama grubu böyle tek unsur tuple sağlamalıdır yüzden, bir tekil olmasına rağmen: (value,).

cursor.execute("""INSERT INTO mytable (fruit) VALUES (%s)""", ('apple',))

0

Bu arada, bunu f-dizeleriyle yapmanın başka bir yolu var :

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

Bunu yapmayın, uygulamayı SQL enjeksiyon saldırılarına açık bırakır.
snakecharmerb

Bundan bahsetmeye değer olduğunu düşündüm. Elbette bu cevabı değişkenlerin daha önce doğrulandığını varsayarak yazıyorum.
Patrik
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.