2013-08-02 4 views
6

sto cercando di selezionare alcuni dati dal database e ho due fette di codice per farlo:selectionArgs in SQLiteQueryBuilder non funziona con valori interi nelle colonne

cursor = builder.query(db, 
        new String[]{"col1", "col2", "col3"}, 
        "id = ?", new String[]{getSID(db)}, null, null, null); 

e

cursor = builder.query(db, 
        new String[]{"col1", "col2", "col3"}, 
        "id = " + getSID(db), null, null, null, null); 

La differenza tra di loro è che il primo sembra essere più corretto secondo la documentazione, ma non funziona - il cursore è vuoto. Invece del secondo - ricevo tutti i dati di cui ho bisogno.

Così ho cercato di eseguire diverse query SQL sul mio PC con una copia del database e questo è quello che ho:

SELECT col1, col2, col3 FROM SomeTables WHERE (id = '42') 

Questo uno non funziona (e questa query è uguale, ovviamente, per interrogare, generato dal primo codice di esempio)

SELECT col1, col2, col3 FROM SomeTables WHERE (id = 42) 

E questo funziona correttamente (equivale alla query dal secondo esempio di codice).

Come noto, SQLite dovrebbe eseguire automaticamente il cast di tipi, ma qualcosa è andato storto e non so perché. Hai qualche idea su come può essere corretto il primo codice di esempio? (? O, forse, database)

Se è importante, qui è semplificato CREATE sceneggiatura del tavolo con id campo:

CREATE TABLE SomeTable (ID PRIMARY KEY, col1, col2, [...]) 

UPD: E, a proposito, GETSID (db) restituisce Stringa Oggetto.

+0

Nella prima query si passa "42". sql executor lo otterrà sempre come stringa in modo da non dover usare "'" (Single Quote). puoi dare direttamente un valore. se stai usando "mi piace" in quel momento hai bisogno di virgolette singole altrimenti va bene. –

risposta

2

Secondo SQLite documentation,

Ogni colonna in un database SQLite versione 3, ad eccezione di una colonna INTEGER PRIMARY KEY, possono essere utilizzati per memorizzare un valore di qualsiasi classe di memoria.

Nel mio caso, ciò significa che non possiamo essere sicuri di quale tipo di dati verrà archiviato nelle colonne. Se è possibile controllare e convertire i tipi di dati quando vengono inseriti nel database, è possibile convertire i valori id in TEXT quando si aggiungono dati al database e si utilizza facilmente selectionArgs. Ma non è una risposta alla mia domanda, perché devo gestire il contenuto del database così com'è.

Quindi, possibili soluzioni:

a) incorporare valori interi in selection stringa senza avvolgendoli in ':

cursor = builder.query(db, 
        new String[]{"col1", "col2", "col3"}, 
        "id = " + getSID(db), null, null, null, null); 

valori b) trasmettere da selectionArgs: CAST(? as INTEGER) o CAST(id AS TEXT). Penso che convertire la colonna in TEXT sia la soluzione migliore, perché l'operando corretto è sempre TEXT, ma quello di sinistra può essere qualsiasi cosa. Quindi:

cursor = builder.query(db, 
        new String[]{"col1", "col2", "col3"}, 
        "CAST(id AS TEXT) = ?", 
        new String[]{getSID(db)}, null, null, null); 
1

è necessario convertire il vostro intid in string prima di passare alla tua richiesta perché la matrice di parametri è di tipo stringa. Ad esempio:

cursor = builder.query(db, new String[]{"col1", "col2", "col3"}, 
    "id = ?", new String[]{String.valueOf(getSID(db))}, null, null, null); 

Il motivo per cui funziona secondo tipo di query è perché si sta aggiungendo il valore intero con stringa che converte automaticamente l'int in stringa. Ad esempio:

int i = 10; 
String s = i + ""; //now 10 is in string 
+0

Mi spiace, ho dimenticato di dire che getSID (db) restituisce oggetto String. Se ritornasse int, avrei appena ottenuto l'errore di compilazione di 'tipi incompatibili '. –

+0

Preferisco il modo con 'String.valueOf (i)', penso che sia più pulito e leggibile dall'uomo penso. – Sajmon

+0

'String.valueOf (String)'? Questa è una sciocchezza. Ho anche provato a rendere 'getSID' return' int' e usare 'String.valueOf', ma non è stato d'aiuto. –

8

I parametri di query possono essere solo stringhe è un errore di progettazione orribile nell'API del database Android.

Nonostante ciò che dice la documentazione, è necessario utilizzare i parametri solo per i valori di stringa effettivi; i valori interi possono essere incorporati in modo sicuro direttamente nella stringa SQL. (Per blob, è necessario utilizzare una funzione che accetta ContentValues.)

Si prega di notare che mentre SQLite utilizza dynamic typing, valori di tipi diversi fanno non risultano uguali nella maggior parte dei casi (SELECT 42='42'; ritorni 0). SQLite fa automaticamente valori convertiti a type affinity (nel tuo caso, ciò avverrebbe se hai dichiarato la colonna id come INTEGER), ma questo è piuttosto controintuitivo, quindi non dovrebbe essere invocato.

+0

Ho provato a dichiarare il campo 'ID' come 'ID INTEGER PRIMARY KEY' e' ID TEXT PRIMARY KEY', ma non è stato di aiuto. C'è un modo per usare selectionArgs senza incorporare i valori nella stringa di selezione? –

+1

Trovato: 'CAST (? As INTEGER)' funziona correttamente. Sembra più un hack sporco, ma funziona. –

+0

Ma, 'CAST (colonna AS TEXT)' dovrebbe essere la soluzione migliore, immagino. –