2011-01-25 11 views
26

tutto quello che voglio fare è inviare una query comeSQLite: lista legano dei valori a "DOVE col IN (: PRM)"

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

Così ho preparato la seguente dichiarazione

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

Poi io uso

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

Purtroppo questo diventa

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

ed è inutile (notare le due citazioni singole aggiuntive). Ho già provato a mettere extra 'nella stringa, ma loro sono fuggiti. Non ho trovato un'opzione per disattivare l'escaping o impedire che il testo venga racchiuso tra virgolette singole. L'ultima cosa che posso pensare non è usare una dichiarazione preparata, ma la prenderei solo come ultima opzione. Avete idee o suggerimenti?

Grazie

Edit:

Il numero di parametri è dinamico, quindi potrebbe essere tre numeri, come nell'esempio di cui sopra, uno o dodici.

risposta

23

È possibile costruire in modo dinamico un'istruzione SQL con parametri della forma

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

e quindi chiamare sqlite_bind_int una volta per ogni "?" hai aggiunto alla dichiarazione.

Non esiste alcun modo per associare direttamente un parametro di testo a più numeri interi (o, per quella materia, più testo).

Ecco pseudo-codice per quello che ho in mente:

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

Grazie per la risposta. Non l'ho menzionato nel mio post originale (appena modificato), ma il numero di parametri è dinamico. In realtà continuo a rispondere come "non possibile", il che significa che semplicemente non posso usare una dichiarazione preparata. – Sebastian

+0

No, Sebastian, il mio suggerimento è di creare dinamicamente un'istruzione SQL con un numero variabile di parametri e quindi chiamare sqlite_bind_in in un ciclo per ogni parametro. Dovrebbe funzionare per te. Aggiungerò pseudo-codice alla risposta. –

+0

Per poter chiamare sql_bind_ * è necessario prima chiamare sql_prepare. Non vedo il punto di creare dinamicamente un'istruzione, prepararla, utilizzare bind, eseguire e finalizzare, invece di inserire i parametri direttamente durante la creazione della query, preparare, eseguire e finalizzare. Ad ogni modo dovrei chiamare sql_prepare ogni volta che voglio eseguire la query ed è quello che vorrei salvare e fare una sola volta. – Sebastian

9

Ho appena affrontato questa domanda me stesso, ma ha risposto con la creazione di una tabella temporanea e l'inserimento di tutti i valori in quella, in modo da poter poi fare :

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

Hai qualche confronto delle prestazioni? Posso immaginare che il sovraccarico di creazione di un tavolo temporaneo superi la creazione del piano di esecuzione. Tuttavia, ciò dipenderà dalle dimensioni della tabella. Immagino che si possa mantenere il tavolo temporaneo in giro e cancellarlo e riutilizzarlo ogni volta (si presume che la sincronizzazione sia corretta). Ancora sarebbe riempire vs piano di esecuzione – Sebastian

+0

Questa è una soluzione dolce. Spedisci i miei ordini di codice di confronto diff di tabelle. –

4

Ancora più semplice, costruire la query come questa:

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

Che lingua è? Giava?! – Sebastian

+3

è python.Che lingua stai cercando? – xtin

0

Working on a sam funzionalità e mi ha portato a questo approccio: (nodejs, ES6, prometto)

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

Ad esempio, se si desidera che la query SQL:

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

Che dire:

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

funziona bene anche (Javascript ES6):

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

È davvero una cattiva idea inserire manualmente i dati in una query in fase di esecuzione. È un grave rischio per la sicurezza che ti lascia aperto a un attacco di SQL injection. https://www.netsparker.com/blog/web-security/sql-injection-cheat-sheet/ – jasonseminara

0

Una risposta molto più semplice e più sicura consiste semplicemente nel generare la maschera (al contrario della parte di dati della query) e consentire al motore del formatter di SQL-injection di fare il proprio lavoro.

Supponiamo di avere alcuni id s in un array, e alcune 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); 
Problemi correlati