Autore Topic: Cambiare il tipo di contenuto delle colonne SQLite dentro onUpgrade  (Letto 1446 volte)

Offline RogoMantiK

  • Utente junior
  • **
  • Post: 61
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Xperia Neo
Tempo fa ho fatto un programma che utilizza un database per memorizzare dei dati. l'onCreate è questo:
Codice (Java): [Seleziona]
@Override
                public void onCreate(SQLiteDatabase db) {
                        //
                        db.execSQL("CREATE TABLE " + DATABASE_TABLE + " (" + KEY_IDRIGA
                                        + " INTEGER PRIMARY KEY AUTOINCREMENT, " + KEY_A
                                        + " TEXT NOT NULL, " + KEY_B + " TEXT NOT NULL);");
                       

                }
e avevo dichiarato
    private static final int DATABASE_VERSION = 1;

adesso vorrei fare l'upgrade passando ad un organizzazione come se avessi eseguito in origine questo comando (e vorrei conservare tutti i dati precedentemente inseriti)
Codice (Java): [Seleziona]
db.execSQL("CREATE TABLE " + DATABASE_TABLE + " (" + KEY_IDRIGA
                                        + " INTEGER PRIMARY KEY AUTOINCREMENT, " + KEY_A
                                        + " TEXT NOT NULL UNIQUE, " + KEY_B + " TEXT NOT NULL UNIQUE);");

Ho tentato di fare
Codice (Java): [Seleziona]
@Override
                public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
                        if (oldVersion < 2) {
                        //db.execSQL("DROP TABLE IF EXIST " + DATABASE_TABLE);
                        db.execSQL("ALTER TABLE " + DATABASE_TABLE+ " (" + KEY_IDRIGA
                                        + " INTEGER PRIMARY KEY AUTOINCREMENT, " + KEY_A
                                        + " TEXT NOT NULL UNIQUE, " + KEY_B + " TEXT NOT NULL UNIQUE);");
                        //onCreate(db);
                        }
dichiarando
         private static final int DATABASE_VERSION = 2;

ma il logcat mi da errore

Codice (Java): [Seleziona]
10-31 11:29:44.812: E/AndroidRuntime(671): Uncaught handler: thread main exiting due to uncaught exception
10-31 11:29:44.832: E/AndroidRuntime(671): java.lang.RuntimeException: Unable to start activity ComponentInfo{free.test.app/free.test.app.Test}: android.database.sqlite.SQLiteException: near "(": syntax error: ALTER TABLE tabella (_id INTEGER PRIMARY KEY AUTOINCREMENT, chiavea TEXT NOT NULL UNIQUE, chiaveb TEXT NOT NULL UNIQUE);
10-31 11:29:44.832: E/AndroidRuntime(671):      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2496)
10-31 11:29:44.832: E/AndroidRuntime(671):      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2512)
10-31 11:29:44.832: E/AndroidRuntime(671):      at android.app.ActivityThread.access$2200(ActivityThread.java:119)
10-31 11:29:44.832: E/AndroidRuntime(671):      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1863)
10-31 11:29:44.832: E/AndroidRuntime(671):      at android.os.Handler.dispatchMessage(Handler.java:99)
10-31 11:29:44.832: E/AndroidRuntime(671):      at android.os.Looper.loop(Looper.java:123)
10-31 11:29:44.832: E/AndroidRuntime(671):      at android.app.ActivityThread.main(ActivityThread.java:4363)
10-31 11:29:44.832: E/AndroidRuntime(671):      at java.lang.reflect.Method.invokeNative(Native Method)
10-31 11:29:44.832: E/AndroidRuntime(671):      at java.lang.reflect.Method.invoke(Method.java:521)
10-31 11:29:44.832: E/AndroidRuntime(671):      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
10-31 11:29:44.832: E/AndroidRuntime(671):      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
10-31 11:29:44.832: E/AndroidRuntime(671):      at dalvik.system.NativeStart.main(Native Method)
10-31 11:29:44.832: E/AndroidRuntime(671): Caused by: android.database.sqlite.SQLiteException: near "(": syntax error: ALTER TABLE tabella (_id INTEGER PRIMARY KEY AUTOINCREMENT, chiavea TEXT NOT NULL UNIQUE, chiaveb TEXT NOT NULL UNIQUE);
10-31 11:29:44.832: E/AndroidRuntime(671):      at android.database.sqlite.SQLiteDatabase.native_execSQL(Native Method)
10-31 11:29:44.832: E/AndroidRuntime(671):      at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1610)
10-31 11:29:44.832: E/AndroidRuntime(671):      at free.test.app.SQLHelper$DbHelper.onUpgrade(SQLHelper.java:49)
10-31 11:29:44.832: E/AndroidRuntime(671):      at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:108)
10-31 11:29:44.832: E/AndroidRuntime(671):      at free.test.app.SQLHelper.openToWrite(SQLHelper.java:71)
10-31 11:29:44.832: E/AndroidRuntime(671):      at free.test.app.Test.onCreate(Test.java:85)
10-31 11:29:44.832: E/AndroidRuntime(671):      at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
10-31 11:29:44.832: E/AndroidRuntime(671):      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2459)
10-31 11:29:44.832: E/AndroidRuntime(671):      ... 11 more


L'applicazione si blocca nel main quando apro il database (at free.test.app.Test.onCreate(Test.java:85))
Il comando ALTER TABLE è corretto per questa situazione?
Non so gestire questa cosa qualcuno mi aiuta?
Dovrei semplicemente ricopiare il database aggiungendo UNIQUE...
Grazie

Offline iceweasel

  • Moderatore globale
  • Utente senior
  • *****
  • Post: 878
  • Respect: +147
    • Mostra profilo
  • Dispositivo Android:
    LGE P990 - Google Nexus 5
  • Sistema operativo:
    Linux Debian Sid
Re:Cambiare il tipo di contenuto delle colonne SQLite dentro onUpgrade
« Risposta #1 il: 31 Ottobre 2012, 16:36:37 CET »
0
L'errore è chiarissimo, basta leggerlo con attenzione:

Citazione
android.database.sqlite.SQLiteException: near "(": syntax error: ALTER TABLE tabella (_id INTEGER PRIMARY KEY AUTOINCREMENT, chiavea TEXT NOT NULL UNIQUE, chiaveb TEXT NOT NULL UNIQUE);

La documentazione ufficiale di SQLite spiega la sintassi di "ALTER TABLE":

SQLite Query Language: ALTER TABLE

non c'è nessuna parentesi, sia aperta che chiusa, e poi anche il resto è sintatticamente sbagliato.

adb logcat | tee /tmp/logcat | grep TAG

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:Cambiare il tipo di contenuto delle colonne SQLite dentro onUpgrade
« Risposta #2 il: 31 Ottobre 2012, 16:53:26 CET »
0
iceweasel ha già detto tutto, mi permetto solo di riportare un'abitudine che trovo molto utile: quando sono insicuro sulle query, prima di provarle nell'applicazione (sia android che qualsiasi altro tipo), le provo in un database manager, in questo caso un sqlite_manager.
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline RogoMantiK

  • Utente junior
  • **
  • Post: 61
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Xperia Neo
Re:Cambiare il tipo di contenuto delle colonne SQLite dentro onUpgrade
« Risposta #3 il: 31 Ottobre 2012, 19:50:11 CET »
0
Ok credo che la parte
It is not possible to rename a column, remove a column, or add or remove constraints from a table.

Quindi dovrei ricopiare il database in uno nuovo in cui ci aggiungo la constraint UNIQUE

Il fatto è che non so come procedere... non sono per niente pratico di SQLite

Offline iceweasel

  • Moderatore globale
  • Utente senior
  • *****
  • Post: 878
  • Respect: +147
    • Mostra profilo
  • Dispositivo Android:
    LGE P990 - Google Nexus 5
  • Sistema operativo:
    Linux Debian Sid
Re:Cambiare il tipo di contenuto delle colonne SQLite dentro onUpgrade
« Risposta #4 il: 31 Ottobre 2012, 21:45:46 CET »
0
Quindi dovrei ricopiare il database in uno nuovo ...

Non serve ricreare tutto il database basta creare una nuova tabella con un nome temporaneo, copiare tutti i dati, cancellare la vecchia tabella e rinominare la nuova tabella con il nome della vecchia.
adb logcat | tee /tmp/logcat | grep TAG

Offline RogoMantiK

  • Utente junior
  • **
  • Post: 61
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Xperia Neo
Re:Cambiare il tipo di contenuto delle colonne SQLite dentro onUpgrade
« Risposta #5 il: 01 Novembre 2012, 12:11:57 CET »
0
Ho fatto qualche prova con il codice qui sotto

creo un database temporaneo con la struttura voluta
Codice (Java): [Seleziona]
db.execSQL("CREATE TABLE " + "tempTable" + " (" + KEY_IDRIGA
                                        + " INTEGER PRIMARY KEY AUTOINCREMENT, " + "keyTEMPa"
                                        + " TEXT NOT NULL UNIQUE, " + "keyTEMPb" + " TEXT NOT NULL UNIQUE);");
Copio i dati dal vecchio DB evitando i duplicati
Codice (Java): [Seleziona]
db.execSQL("INSERT INTO " + "tempTable" +" (" + KEY_IDRIGA + ", " + "keyTEMPa" + ", " + "keyTEMPb" +")"
                                        + " SELECT " + "*" + " FROM " + DATABASE_TABLE + " WHERE " + DATABASE_TABLE + "." + KEY_A + " NOT IN (SELECT " + "keyTEMPa" + " FROM " + "tempTable" + ")");

Poi ho dei comandi che:
1 Cancellano il vecchio database
2 Ne creano uno nuovo con i nomi di colonna corretti
3 Copio i dati dal database temporaneo in quello nuovo
4 Cancello il database temporaneo


Se faccio l'aggiornamento da un'applicazione che ha duplicati ottengo errore
Il logcat mi dice   keyTEMPb  non è unica
Se aggiorno da un applicazione senza duplicati funziona tutto (database copiato e niente duplicati per i nuovi inserimenti)

In pratica quando trova un duplicato si blocca invece dovrebbe saltarlo e copiare il successivo
Dove è il mio errore?


POST EDIT
Forse ho corretto l'errore, se chi legge trova qualcosa di sbagliato scriva la sua soluzione o l'approccio più corretto

In pratica ho sostituito TEXT NOT NULL UNIQUE
con TEXT NOT NULL UNIQUE ON CONFLICT IGNORE

mentre INSERT INTO
con INSERT OR IGNORE INTO

sembra funzionare. se non trovo errori e se nessuno rettifica tra un paio di giorni marco il post come risolto
« Ultima modifica: 01 Novembre 2012, 12:37:35 CET da RogoMantiK »

Offline iceweasel

  • Moderatore globale
  • Utente senior
  • *****
  • Post: 878
  • Respect: +147
    • Mostra profilo
  • Dispositivo Android:
    LGE P990 - Google Nexus 5
  • Sistema operativo:
    Linux Debian Sid
Re:Cambiare il tipo di contenuto delle colonne SQLite dentro onUpgrade
« Risposta #6 il: 01 Novembre 2012, 13:52:00 CET »
0
Qui è spiegato cosa fare in caso di conflitti:

SQLite Query Language: ON CONFLICT clause

nel tuo codice usi "ON CONFLICT IGNORE"  per conservare il primo dato, se vuoi invece l'ultimo devi usare"ON CONFLICT REPLACE", dipende quale consideri più importante.

Come dice bradipao non serve fare le prove sul dispositivo, basta usare qualche font-end o il programma "sqlite3" presente nei tool di Android per caricare il database e fare tutte le prove fino a trovare i comandi SQL più adatti e robusti.
adb logcat | tee /tmp/logcat | grep TAG