2011-01-25 21 views
26

tất cả tôi muốn làm là gửi một truy vấn nhưSQLite: danh sách ràng buộc của các giá trị để "WHERE col IN (: PRM)"

SELECT * FROM table WHERE col IN (110, 130, 90); 

Vì vậy, tôi đã chuẩn bị báo cáo kết quả sau

SELECT * FROM table WHERE col IN (:LST); 

Sau đó, tôi sử dụng

sqlite_bind_text(stmt, 1, "110, 130, 90", -1, SQLITE_STATIC); 

Đáng tiếc là điều này trở thành

SELECT * FROM table WHERE col IN ('110, 130, 90'); 

và vô dụng (lưu ý hai dấu nháy đơn bổ sung). Tôi đã thử đặt thêm vào 'trong chuỗi nhưng họ đã trốn thoát. Tôi không tìm thấy một tùy chọn để tắt thoát hoặc ngăn văn bản bị kèm theo dấu nháy đơn. Điều cuối cùng tôi có thể nghĩ đến là không sử dụng một tuyên bố chuẩn bị, nhưng tôi chỉ lấy nó như là lựa chọn cuối cùng. Bạn có ý tưởng hay đề xuất gì không?

Cảm ơn

Edit:

Số lượng các thông số rất linh hoạt, vì vậy nó có thể là ba con số, như trong ví dụ trên, một hoặc mười hai.

Trả lời

23

Bạn có thể chủ động xây dựng một câu lệnh SQL tham số của mẫu

SELECT * FROM TABLE WHERE col IN (?, ?, ?) 

và sau đó gọi sqlite_bind_int một lần cho mỗi "?" bạn đã thêm vào câu lệnh.

Không có cách nào để ràng buộc trực tiếp một tham số văn bản với nhiều tham số nguyên (hoặc, cho rằng, nhiều văn bản).

Dưới đây là mã giả cho những gì tôi có trong tâm trí:

-- Args is an array of parameter values 
for i = Lo(Args) to Hi(Args) 
    paramlist = paramlist + ', ?' 

sql = 'SELECT * FROM TABLE WHERE col IN (' + Right(paramlist, 3) + ')' 

for i = Lo(Args) to Hi(Args) 
    sql_bind_int(sql, i, Args[i] 

-- execute query here. 
+0

Cảm ơn trả lời của bạn. Tôi đã không đề cập đến nó trong bài viết gốc của tôi (chỉ cần chỉnh sửa), nhưng số lượng các tham số là năng động. Tôi thực sự vẫn lấy câu trả lời của bạn là "không thể", có nghĩa là tôi chỉ đơn giản là không thể sử dụng một tuyên bố chuẩn bị. – Sebastian

+0

Không, Sebastian, đề nghị của tôi là tự động xây dựng một câu lệnh SQL với một số biến tham số và sau đó gọi sqlite_bind_in trong một vòng lặp cho mỗi tham số. Nó sẽ làm việc cho bạn. Tôi sẽ thêm mã giả vào câu trả lời. –

+0

Để có thể gọi sql_bind_ * người ta cần gọi sql_prepare trước. Tôi không thấy điểm trong xây dựng động một câu lệnh, chuẩn bị nó, sử dụng bind, execute và finalize, thay vì chèn trực tiếp các tham số khi xây dựng truy vấn, chuẩn bị, thực hiện và hoàn thành. Dù bằng cách nào tôi sẽ cần phải gọi sql_prepare mỗi khi tôi muốn thực hiện truy vấn và đó là những gì tôi muốn lưu và chỉ làm một lần. – Sebastian

9

Tôi chỉ phải đối mặt với câu hỏi này bản thân mình, nhưng đã trả lời nó bằng cách tạo ra một bảng tạm thời và chèn tất cả các giá trị vào đó, vì vậy mà tôi sau đó có thể làm :

SELECT * FROM TABLE WHERE col IN (SELECT col FROM temporarytable); 
+0

Bạn có bất kỳ so sánh hiệu suất nào không? Tôi có thể tưởng tượng rằng chi phí tạo bảng tạm thời lớn hơn quá trình tạo kế hoạch thực hiện. Tuy nhiên, điều đó sẽ phụ thuộc vào kích thước bảng .. Tôi đoán người ta có thể giữ bảng tạm thời xung quanh và rõ ràng và tái sử dụng nó mỗi lần (giả định đồng bộ hóa thích hợp). Tuy nhiên nó sẽ được làm đầy vs kế hoạch thực hiện – Sebastian

+0

Đó là một giải pháp ngọt ngào. Đã tăng tốc các đơn hàng mã của tôi so sánh bảng khác biệt. –

4

Thậm chí đơn giản, xây dựng truy vấn của bạn như thế này:

"SELECT * FROM TABLE WHERE col IN ("+",".join(["?"]*len(lst))+")" 
+0

Ngôn ngữ đó là gì? Java ?! – Sebastian

+3

đó là python.Bạn đang tìm kiếm ngôn ngữ nào? – xtin

0

Làm việc trên một sam chức năng e đưa tôi đến với cách tiếp cận này: (nodejs, es6, Promise)

var deleteRecords = function (tblName, data) { 
     return new Promise((resolve, reject) => { 
      var jdata = JSON.stringify(data); 
      this.run(`DELETE FROM ${tblName} WHERE id IN (?)`, jdata.substr(1, jdata.length - 2), function (err) { 
       err ? reject('deleteRecords failed with : ' + err) : resolve(); 
      }); 
     }); 
    }; 
0

Ví dụ, nếu bạn muốn truy vấn sql:

select * from table where col in (110, 130, 90) 

gì về:

my_list = [110, 130, 90] 
my_list_str = repr(my_list).replace('[','(').replace(']',')') 
cur.execute("select * from table where col in %s" % my_list_str) 
0

công trình này hoạt động tốt (Javascript ES6):

let myList = [1, 2, 3]; 
`SELECT * FROM table WHERE col IN (${myList.join()});` 
+0

Đó là một ý tưởng thực sự tồi để tự chèn dữ liệu vào một truy vấn trong thời gian chạy. Đó là một nguy cơ bảo mật lớn khiến bạn mở cuộc tấn công SQL-injection. https://www.netsparker.com/blog/web-security/sql-injection-cheat-sheet/ – jasonseminara

0

Câu trả lời đơn giản hơn và an toàn hơn đơn giản liên quan đến việc tạo mặt nạ (trái với phần dữ liệu của truy vấn) và cho phép công cụ định dạng SQL injection thực hiện công việc của nó.

Giả sử chúng ta có một số id s trong một mảng, và một số cb callback:

/* we need to generate a '?' for each item in our mask */ 
const mask = Array(ids.length).fill('?').join(); 

db.get(` 
    SELECT * 
    FROM films f 
    WHERE f.id 
     IN (${mask}) 
`, ids, cb); 
Các vấn đề liên quan