2011-01-25 9 views
26

wszystko co chcę zrobić, to wysłać zapytanie jakSQLite: lista wiążą się z wartościami z "WHERE col IN (: PRM)"

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

Więc przygotowałem następujące oświadczenie

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

Następnie używam

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

Niestety ta staje

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

i jest bezużyteczny (zwróć uwagę na dwie dodatkowe pojedyncze cytaty). Próbowałem już wstawić dodatkowe "w sznurku, ale oni uciekli. Nie znalazłem możliwości wyłączenia funkcji unikania lub uniemożliwienia zawarcia tekstu pojedynczym cudzysłowem. Ostatnią rzeczą, o której myślę, że nie używam przygotowanego oświadczenia, ale biorę to tylko jako ostatnią opcję. Czy masz jakieś pomysły lub sugestie?

Dzięki

Edit:

Liczba parametrów jest dynamiczna, więc może to być trzy numery, jak w powyższym przykładzie, jedna lub dwanaście.

Odpowiedz

23

Można dynamicznie zbudować sparametryzowana SQL formularza

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

a następnie zadzwonić sqlite_bind_int raz dla każdego „?” dodałeś do wyciągu.

Nie ma możliwości bezpośredniego powiązania parametru tekstowego z wieloma liczbami całkowitymi (lub, jeśli o to chodzi, wieloma tekstami).

Oto pseudokod za to, co mam na myśli:

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

Dzięki za odpowiedź. Nie wspominałem o tym w moim oryginalnym wpisie (właśnie edytowanym), ale liczba parametrów jest dynamiczna. Właściwie nadal przyjmuję twoją odpowiedź jako "nie możliwe", co oznacza, że ​​po prostu nie mogę użyć przygotowanego oświadczenia. – Sebastian

+0

Nie, Sebastian, moja sugestia polega na dynamicznym budowaniu instrukcji SQL ze zmienną liczbą parametrów, a następnie wywoływanie sqlite_bind_in w pętli dla każdego parametru. To powinno działać dla ciebie. Dodam pseudo-kod do odpowiedzi. –

+0

Aby móc wywołać sql_bind_ *, należy najpierw wywołać sql_prepare. Nie widzę sensu w dynamicznym budowaniu instrukcji, przygotowywaniu jej, używaniu bindowania, wykonywaniu i sfinalizowaniu, zamiast wstawiania parametrów bezpośrednio podczas budowania zapytania, przygotowania, wykonania i sfinalizowania. Tak czy inaczej, powinienem wywoływać sql_prepare za każdym razem, gdy chcę wykonać zapytanie i to jest to, co chciałbym zapisać i zrobić tylko raz. – Sebastian

9

Właśnie wychodził na to pytanie sam, ale odpowiedział go poprzez tworzenie tabeli tymczasowej i wkładając wszystkie wartości w tym, abym mógł wtedy zrobić :

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

Czy masz porównanie wydajności? Mogę sobie wyobrazić, że obciążenie związane z tworzeniem tymczasowej tabeli przewyższa tworzenie planu wykonania. To jednak będzie zależeć od wielkości tabel .. Myślę, że można zachować tabelę tymczasową i wyczyścić ją i użyć ponownie za każdym razem (zakłada się prawidłową synchronizację). Nadal byłoby to wypełnienie vs plan wykonania – Sebastian

+0

To jest słodkie rozwiązanie. Przyspieszyłem moje rozkazy kodowe porównania różnic tabelarycznych. –

4

jeszcze prostsze, zbudować zapytanie tak:

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

Jaki to jest język? Jawa?! – Sebastian

+3

to jest python.W jakim języku szukasz? – xtin

0

Praca na Sam Funkcjonalność e doprowadzić mnie do takiego podejścia: (nodejs, ES6 obietnica)

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

Na przykład, jeśli chcesz zapytanie SQL:

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

Co o:

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

to działa również dobrze (Javascript ES6):

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

To naprawdę zły pomysł, aby ręcznie wprowadzić dane do zapytania w środowisku wykonawczym. Jest to poważne zagrożenie dla bezpieczeństwa, które otwiera cię na atak polegający na wstrzyknięciu SQL. https://www.netsparker.com/blog/web-security/sql-injection-cheat-sheet/ – jasonseminara

0

O wiele prostsza i bezpieczniejsza odpowiedź polega na wygenerowaniu maski (w przeciwieństwie do części danych zapytania) i umożliwieniu silnikowi formatowania z wtryskiem SQL wykonania swojej pracy.

Załóżmy, że mamy pewne id sw tablicy, a niektóre cb zwrotna:

/* 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);