2010-02-12 24 views
8

Với đặc tả DB API của Python, bạn có thể chuyển đối số tham số đến phương thức execute(). Một phần của tuyên bố của tôi là một mệnh đề WHERE IN và tôi đã sử dụng một bộ dữ liệu để điền vào IN. Ví dụ:Gửi thông số cho DB .execute cho WHERE IN ... INT danh sách

params = ((3, 2, 1),) 
stmt = "SELECT * FROM table WHERE id IN %s" 
db.execute(stmt, params) 

Nhưng khi tôi chạy vào trường hợp tham số chỉ là một bộ gồm 1 mục, thực thi không thành công.

ProgrammingError: ERROR: syntax error at or near ")"
LINE 13: WHERE id IN (3,)

Làm cách nào để tôi có được bộ dữ liệu hoạt động đúng với điều khoản?

Trả lời

8

Chỉnh sửa: Xin lưu ý: như @rspeer đề cập trong nhận xét, hãy thận trọng để bảo vệ bản thân khỏi tấn công SQL injection.

Testing với pg8000 (một DB-API 2.0 tương thích giao diện Pure-Python vào cơ sở dữ liệu PostgreSQL):

Đây là cách đề nghị để vượt qua nhiều tham số để một khoản "IN".

params = [3,2,1] 
stmt = 'SELECT * FROM table WHERE id IN (%s)' % ','.join('%s' for i in params) 
cursor.execute(stmt, params) 

Một biên tập (kiểm tra đầy đủ và ví dụ làm việc):

>>> from pg8000 import DBAPI 
>>> conn = DBAPI.connect(user="a", database="d", host="localhost", password="p") 
>>> c = conn.cursor() 
>>> prms = [1,2,3] 
>>> stmt = 'SELECT * FROM table WHERE id IN (%s)' % ','.join('%s' for i in prms) 
>>> c.execute(stmt,prms) 
>>> c.fetchall() 
((1, u'myitem1'), (2, u'myitem2'), (3, u'myitem3')) 
+1

Sửa tôi nếu tôi sai, nhưng ví dụ của bạn không chỉ chuyển mục đầu tiên đến mệnh đề IN? > CHỌN * TỪ bảng WHERE id IN (3) –

+0

@John: bạn nói đúng, cảm ơn. Cập nhật câu trả lời với nhiều thông tin hơn. – bernie

+1

Cảm ơn bạn, Adam. –

1

Lỗi đến từ dấu phẩy sau 3. Chỉ cần để lại cho các giá trị đơn lẻ và bạn đã đặt.

params = ((3), ...) 
stmt = "SELECT * FROM table WHERE id IN %s" 
db.execute(stmt, params) 
+0

Vâng, tôi biết tại sao lỗi xảy ra, nhưng tôi không xây dựng bộ dữ liệu. Tuple được điền bởi một kết quả SQL khác. Vì vậy, trong đi qua, các mục duy nhất tuple giữ lại một dấu phẩy treo. –

+0

Tôi cũng muốn chỉ ra rằng một tuple mục đơn lẻ phải có dấu phẩy sau. –

+0

Ah, tôi hiểu lầm. Trong trường hợp đó, bạn có thể sử dụng len() để lấy chiều dài của tuple và nếu nó là một tuple sử dụng [0] để trích xuất giá trị không có dấu phẩy. – Daniel

1

Điều này có thể không phải là một câu trả lời chính xác câu hỏi bạn hỏi, nhưng tôi nghĩ rằng nó có thể giải quyết vấn đề mà bạn có.

DB-API của Python dường như không cung cấp cho bạn cách truyền các bộ dữ liệu như các tham số được thay thế an toàn. Câu trả lời được chấp nhận từ bernie là sử dụng toán tử Python % để thay thế, không an toàn.

Tuy nhiên, bạn có thể không phải chuyển tuples làm tham số, đặc biệt khi tuple bạn muốn là kết quả của truy vấn SQL khác (như bạn đã chỉ ra cho Daniel). Thay vào đó, bạn có thể sử dụng các truy vấn phụ SQL.

Nếu tập các ID bạn muốn tại khoản IN là kết quả của SELECT id FROM other_table WHERE use=true, ví dụ:

stmt = "SELECT * FROM table WHERE id IN (SELECT id FROM other_table WHERE use=true)" 
db.execute(stmt) 

Và điều này có thể được tham số (cách an toàn), quá. Nếu ID bạn muốn chọn là những ID có một số parent_id nhất định:

stmt = "SELECT * FROM table WHERE id IN (SELECT id FROM other_table WHERE parent_id=%s)" 
params = (parent_id,) 
db.execute(stmt, params) 
0

Câu trả lời được chấp nhận có nguy cơ Tiêm SQL; bạn sẽ không bao giờ phải chuyển trực tiếp đầu vào của người dùng vào cơ sở dữ liệu. Thay vào đó, hãy tạo truy vấn với số lượng trình giữ chỗ chính xác, sau đó để pg8000 thực hiện thoát:

params = [3,2,1] 
# SELECT * from table where id in (%s,%s,%s) 
stmt = 'SELECT * FROM table WHERE id IN ({})'.format(','.join(['%s']*len(params))) 
cursor.execute(stmt, tuple(params)) 
+0

Điều này có giống với câu trả lời được chấp nhận không? Nó cũng tạo ra một truy vấn với số lượng đúng chỗ dành sẵn, không thay thế các tham số trực tiếp vào chuỗi truy vấn. – BrenBarn

Các vấn đề liên quan