Làm thế nào để sử dụng các biến trong câu lệnh SQL bằng Python?


91

Ok vì vậy tôi không có kinh nghiệm về Python.

Tôi có mã Python sau:

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

đâu var1là số nguyên, var2& var3là các chuỗi.

Làm cách nào để viết tên biến mà không có python bao gồm chúng như một phần của văn bản truy vấn?

Câu trả lời:


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

Lưu ý rằng các tham số được truyền dưới dạng một bộ giá trị.

API cơ sở dữ liệu thực hiện thoát và trích dẫn các biến một cách thích hợp. Hãy cẩn thận không sử dụng toán tử định dạng chuỗi ( %), bởi vì

  1. nó không thực hiện bất kỳ thoát hoặc trích dẫn.
  2. nó dễ bị tấn công định dạng chuỗi không được kiểm soát, ví dụ như SQL injection .

Thật thú vị, tại sao nó hoạt động với các vars riêng biệt thay vì trong một mảng (var1, var2, var3)?
Andomar

Theo thông số kỹ thuật của API DB, có vẻ như nó có thể là một trong hai cách: python.org/dev/peps/pep-0249
Ayman Hourieh

9
@thekashyap Đọc lại cẩn thận. Điều không an toàn là sử dụng toán tử định dạng chuỗi %. Trong thực tế, tôi nói như vậy trong câu trả lời.
Ayman Hourieh

lỗi của tôi .. Tôi đã tưởng tượng ra một % thay vì nằm giữa ,chuỗi và các biến .. không thể hoàn tác bỏ phiếu của tôi do nhiều lý do khác nhau .. Cá nhân tôi muốn thấy các từ như không an toàn / tấn công, v.v. được đề cập trong mô tả nơi bạn nói don 't sử dụng %..
Kashyap

1
@eric câu trả lời cho biết không sử dụng % toán tử để định dạng chuỗi. Những người %trong chuỗi đang được sử dụng cursor.executetrực tiếp và vì nó biết nó đang tạo ra SQL nên nó có thể làm nhiều việc hơn để bảo vệ bạn.
Mark Ransom

66

Các triển khai khác nhau của Python DB-API được phép sử dụng các trình giữ chỗ khác nhau, vì vậy bạn sẽ cần tìm hiểu xem mình đang sử dụng trình giữ chỗ nào - nó có thể là (ví dụ: với MySQLdb):

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

hoặc (ví dụ: với sqlite3 từ thư viện chuẩn Python):

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

hoặc những người khác (sau khi VALUESbạn có thể có (:1, :2, :3), hoặc "kiểu được đặt tên" (:fee, :fie, :fo)hoặc (%(fee)s, %(fie)s, %(fo)s)nơi bạn chuyển một dict thay vì bản đồ làm đối số thứ hai execute). Kiểm tra paramstylehằng số chuỗi trong mô-đun API DB bạn đang sử dụng và tìm tham số tại http://www.python.org/dev/peps/pep-0249/ để xem tất cả các kiểu truyền tham số là gì!


Có thể làm điều tương tự nhưng với tập lệnh SQL bên ngoài không?
Novitoll

46

Nhiều cách. KHÔNG sử dụng cái rõ ràng nhất ( %svới %) trong mã thực, nó dễ bị tấn công .

Đây là copy-paste'd từ pydoc của 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)

Thêm ví dụ nếu bạn cần:

# 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
Một số triển khai DB-API thực sự sử dụng% s cho các biến của chúng - đáng chú ý nhất là psycopg2 cho PostgreSQL. Điều này không được nhầm lẫn (mặc dù nó dễ dàng như vậy) với việc sử dụng% s với toán tử% để thay thế chuỗi. Tôi thực sự rất vui nếu, vì tính di động, chúng ta có thể có một cách chuẩn xác định để chỉ định các tham số SQL cho DB-API.
ThatAintWorking

24

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

Hãy cẩn thận khi bạn chỉ cần thêm giá trị của các biến vào câu lệnh của mình: Hãy tưởng tượng một người dùng tự đặt tên cho mình ';DROP TABLE Users;'- Đó là lý do tại sao bạn cần sử dụng sql Escape, Python cung cấp cho bạn khi bạn sử dụng con trỏ.execute một cách hợp lý. Ví dụ trong url là:

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

13
Trên thực tế, nó không phải là SQL thoát. Đó là ràng buộc biến, đơn giản và trực tiếp hơn nhiều. Các giá trị được liên kết vào câu lệnh SQL sau khi phân tích cú pháp, giúp nó miễn nhiễm với bất kỳ cuộc tấn công chèn ép nào.
S.Lott

tốt, cho dù đó là SQL thoát hay ràng buộc biến tùy thuộc vào mức độ tốt hay xấu của máy chủ cơ sở dữ liệu / trình điều khiển DB-API của bạn. Tôi đã thấy một số cơ sở dữ liệu sản xuất trong thế giới thực, được triển khai rộng rãi có trình điều khiển DB-API của chúng chỉ thực hiện việc thoát, thay vì giữ dữ liệu và mã ngoài băng tần trên dây. Không cần phải nói, tôi không mấy tôn trọng cái gọi là "cơ sở dữ liệu".
Charles Duffy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.