Jak używać zmiennych w instrukcji SQL w Pythonie?


94

Ok, więc nie mam takiego doświadczenia w Pythonie.

Mam następujący kod w Pythonie:

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

gdzie var1jest liczbą całkowitą, var2i var3są łańcuchami.

Jak mogę napisać nazwy zmiennych bez Pythona, włączając je jako część tekstu zapytania?

Odpowiedzi:


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

Zwróć uwagę, że parametry są przekazywane jako krotka.

Interfejs API bazy danych wykonuje poprawne ucieczki i cytowanie zmiennych. Uważaj, aby nie używać operatora formatowania ciągu ( %), ponieważ

  1. nie stosuje żadnych znaków ucieczki ani cytowania.
  2. jest podatny na ataki w niekontrolowanym formacie string, np . iniekcja SQL .

Ciekawe, dlaczego to działa ze zmiennymi oddzielnie zamiast w tablicy (var1, var2, var3)?
— Andomar

Zgodnie ze specyfikacją DB API wygląda na to, że może to być w obie strony: python.org/dev/peps/pep-0249
— Ayman Hourieh

9
@thekashyap Przeczytaj ponownie uważnie. Niezabezpieczone jest użycie operatora formatowania ciągu %. W rzeczywistości tak mówię w odpowiedzi.
— Ayman Hourieh

mój błąd .. Wyobraziłem sobie, że % zamiast ,między ciągiem a zmiennymi .. nie mogę cofnąć mojego głosowania z różnych powodów .. Osobiście chciałbym zobaczyć słowa takie jak niepewny / atak itp. wymienione w opisie, w którym mówisz nie 't use %..
— Kashyap,

1
@eric odpowiedź mówi, że nie używaj % operatora do formatowania ciągu. Te %w łańcuchu są używane cursor.executebezpośrednio, a ponieważ wie, że generuje kod SQL, może zrobić więcej, aby Cię chronić.
— Mark Ransom

69

Różne implementacje Python DB-API mogą używać różnych symboli zastępczych, więc musisz dowiedzieć się, którego z nich używasz - może to być (np. Z MySQLdb):

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

lub (np. z sqlite3 ze standardowej biblioteki Pythona):

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

lub jeszcze inne (po VALUEStym, jak mogłeś mieć (:1, :2, :3)lub „nazwane style” (:fee, :fie, :fo)lub gdy (%(fee)s, %(fie)s, %(fo)s)przekazujesz dykt zamiast mapy jako drugi argument execute). Sprawdź paramstylestałą łańcuchową w module DB API, którego używasz, i poszukaj paramstyle na http://www.python.org/dev/peps/pep-0249/, aby zobaczyć, jakie są wszystkie style przekazywania parametrów!


Czy można zrobić to samo, ale z zewnętrznym skryptem SQL?
— Novitoll

48

Wiele sposobów. NIE używaj najbardziej oczywistego ( %sz %) w prawdziwym kodzie, jest on otwarty na ataki .

Tutaj skopiuj i wklej z pydoc z 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)

Więcej przykładów, jeśli potrzebujesz:

# 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
Niektóre implementacje DB-API faktycznie używają% s do swoich zmiennych - w szczególności psycopg2 dla PostgreSQL. Nie należy tego mylić (choć łatwo jest) z użyciem% s z operatorem% do zamiany łańcucha. Byłoby naprawdę miło, gdybyśmy ze względu na przenośność mogli mieć zdefiniowany standardowy sposób określania parametrów SQL dla DB-API.
— ThatAintWorking

26

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

Zachowaj ostrożność, gdy po prostu dołączasz wartości zmiennych do swoich instrukcji: Wyobraź sobie użytkownika nazywającego siebie ';DROP TABLE Users;'- dlatego musisz użyć funkcji ucieczki sql, którą Python zapewnia ci, gdy używasz kursor.execute w przyzwoity sposób. Przykład w adresie URL to:

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

13
W rzeczywistości nie jest to ucieczka SQL. To zmienne wiązanie, które jest znacznie prostsze i bardziej bezpośrednie. Wartości są wiązane z instrukcją SQL po przeanalizowaniu, dzięki czemu jest odporna na atak iniekcyjny.
— S.Lott,

cóż, to, czy jest to ucieczka SQL, czy powiązanie zmiennej, zależy od tego, jak dobry lub zły jest twój serwer bazy danych / sterownik DB-API. Widziałem rzeczywiste, szeroko rozpowszechnione produkcyjne bazy danych, w których ich sterownik DB-API po prostu ucieka, zamiast utrzymywać dane i kod poza pasmem. Nie trzeba dodawać, że nie mam wielkiego szacunku do tych tak zwanych „baz danych”.
— Charles Duffy
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.