SQL SQLite Problem mit INSERT

FaKer

Cadet 4th Year
Registriert
Jan. 2004
Beiträge
100
Hallo zusammen,

ich habe ein mMn sehr merkwürdiges Problem bzgl. eines SQLite-INSERT.

Hier erstmal das Code-Schnipsel um das es geht, darunter dann die weitere Fehlerbeschreibung:

Code:
/**
   * Fügt Timestamp-Preis-Kombinationen in die SQLite-DB ein. Im Anschluss daran, werden Datensätze, die älter als 7 Tage sind, gelöscht.
   * @param JSONArray Aus den Array-Elementen müssen direkt JSONObjekte erstellt werden können, in der Form timestamp, price
   */
  public void setSps(JSONArray jsonArray) {
    String sql_insert = "INSERT OR IGNORE INTO " + SpsTbl.TABLE_NAME + "(" + SpsTbl.TIMESTAMP + "," + SpsTbl.PREIS + ")" +
                        " VALUES (?,?)";
    String sql_delete = "DELETE FROM " +SpsTbl.TABLE_NAME +
                        " WHERE " + SpsTbl.TIMESTAMP + " <= STRFTIME('%s','now','-7 days')";
    
    dbConn = db.getWritableDatabase();
    try {
      for(int i = 0; i < jsonArray.length(); i++) {
        JSONObject jsonObj = jsonArray.getJSONObject(i);
        Log.d(TAG, "dbConn.isDbLockedByCurrentThread(): " + dbConn.isDbLockedByCurrentThread());
        Log.d(TAG, "dbConn.isDbLockedByOtherThreads(): " + dbConn.isDbLockedByOtherThreads());
        Log.d(TAG, "dbConn.isOpen(): " + dbConn.isOpen());
        Log.d(TAG, "dbConn.isReadOnly(): " + dbConn.isReadOnly());
        Log.d(TAG, "jsonObj.getString(timestamp): " + jsonObj.getString("timestamp"));
        Log.d(TAG, "jsonObj.getString(price): " + jsonObj.getString("price"));
        dbConn.rawQuery(sql_insert, new String[] { jsonObj.getString("timestamp") , jsonObj.getString("price") });
      }
      
      dbConn.rawQuery(sql_delete, null);
      
    } catch (JSONException e) {
      e.printStackTrace();
    } catch (Exception e) {
      e.printStackTrace();
    }   
  }

Ich bekomme von einem REST-Service Daten, die Prognosen für die nächsten 24 Stunden darstellen. Um mit diesen Daten etwas anfangen zu können, speicher ich sie in der SQLite-DB. Es lässt sich leider nicht vermeiden, dass ich von dem REST-Request Datensätze zurückgeliefert bekomme, die bereits in der Datenbank stehen. Beim Insert bekam ich dann immer die Fehlermeldung: "Error Code 19: Constraint blablabla". Um dieses Problem zu Umgehen, habe ich das INSERT-Stmt. um "OR IGNORE" erweitert. Dadurch sollten Datensätze die bereits vorhanden sind einfach ignoriert werden.
Nun besteht aber das Problem, dass auch die neuen Werte nicht in die DB geschrieben werden.

Hier mal ein Beispiel:

In meiner DB stehen Datensätze bis zu einem Timestamp: 1299916800 Preis: 25

Über meine Log-Ausgaben kann ich mir ja anzeigen lassen, welche Daten ich von dem Service geliefert bekomme.
Dies wären z.B.:
Code:
03-11 10:04:42.590: DEBUG/SmartHomeDBInterface(1658): jsonObj.getString(timestamp): 1299918600
03-11 10:04:42.590: DEBUG/SmartHomeDBInterface(1658): jsonObj.getString(price): 25
...
03-11 10:04:42.590: DEBUG/SmartHomeDBInterface(1658): jsonObj.getString(timestamp): 1299920400
03-11 10:04:42.600: DEBUG/SmartHomeDBInterface(1658): jsonObj.getString(price): 25

Also alles Werte die in der Zukunft liegen und auch noch nicht in der DB vorhanden sind.
Timestamp ist dabei der PK, der Preis kann sich beliebig oft wiederholen.

Liegt das nun evtl. an dem "IGNORE", dass das INSERT auch bei schon vorhandenem Preis ignoriert?

Irgendjemand eine Idee? :/ Vielen Dank schon mal!
 
nimm doch erstmal nen sql-manager o.ä. und führe den reinen sql-code aus und isolieren die db-programmierung.
 
Ist das Android? Weil dann würde ich nicht rawQuery, sondern die insert() Methode verwenden. Weiss allerdings nicht, ob das dein Problem verursacht.
 
Ups, jep, ist Android... @tim0975: werd das gliech mal machen und dann rückmeldung geben
 
Also rawQuery liefert ja einen Cursor zurück. Da du den jedoch nicht per close() schließt, könnte ich mir vorstellen, dass dann im Hintergrund ein ReadLock gehalten wird und somit keine Schreibzugriffe mehr möglich sind. Wenn dem so wäre, dürfte allerdings eig nur der erste Schreibzugriff gelingen.
 
tm0975 schrieb:
nimm doch erstmal nen sql-manager o.ä. und führe den reinen sql-code aus und isolieren die db-programmierung.

Also, wenn ich das ganze auf der Console teste, dann funktionierts
( INSERT OR IGNORE INTO sps(timestamp,preis) VALUES(1299925800,25); )

Ich habe bei Android die Möglichkeit den Insert via ContentValues und insert() durchzuführen.

Das funktioniert auch!
Allerdings bekomm ich dann für jeden vorhandenen Datensatz ne Fehlermeldung (Error Code 19 Constraint blablabla). Diese bringt das Programm zwar nicht zum Absturz, aber ist halt iwo unschön...

dann wirds wohl iwie mit dem dbConn.rawQuery zu tun haben... bekomme jetzt nämlich noch folgenden Hinweis:

Code:
03-11 11:39:47.510: WARN/SQLiteCompiledSql(534): Releasing statement in a finalizer. Please ensure that you explicitly call close() on your cursor: INSERT INTO sps(timestamp,preis) VALUES(?,?)
03-11 11:39:47.510: WARN/SQLiteCompiledSql(534): android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here
03-11 11:39:47.510: WARN/SQLiteCompiledSql(534):     at android.database.sqlite.SQLiteCompiledSql.<init>(SQLiteCompiledSql.java:62)
03-11 11:39:47.510: WARN/SQLiteCompiledSql(534):     at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:100)
03-11 11:39:47.510: WARN/SQLiteCompiledSql(534):     at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:46)
03-11 11:39:47.510: WARN/SQLiteCompiledSql(534):     at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:42)
03-11 11:39:47.510: WARN/SQLiteCompiledSql(534):     at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1345)
03-11 11:39:47.510: WARN/SQLiteCompiledSql(534):     at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1315)
03-11 11:39:47.510: WARN/SQLiteCompiledSql(534):     at de.smarthome.db.SmartHomeDBInterface.setSps(SmartHomeDBInterface.java:105)
03-11 11:39:47.510: WARN/SQLiteCompiledSql(534):     at de.smarthome.services.NetzwerkService._getSps(NetzwerkService.java:87)
03-11 11:39:47.510: WARN/SQLiteCompiledSql(534):     at de.smarthome.services.NetzwerkService.access$3(NetzwerkService.java:78)
03-11 11:39:47.510: WARN/SQLiteCompiledSql(534):     at de.smarthome.services.NetzwerkService$NetzwerkServiceBinder$2.run(NetzwerkService.java:68)
Ergänzung ()

cx01 schrieb:
Also rawQuery liefert ja einen Cursor zurück. Da du den jedoch nicht per close() schließt, könnte ich mir vorstellen, dass dann im Hintergrund ein ReadLock gehalten wird und somit keine Schreibzugriffe mehr möglich sind. Wenn dem so wäre, dürfte allerdings eig nur der erste Schreibzugriff gelingen.

Jo, stimmt!

Ich hab mir grad nochmal die API zur SQLiteDatabase angeschaut.
Es gibt noch die Möglichkeit ein execSQL(String stmt) auszuführen. Das liefert keinen Cursor zurück und somit hab ich das Close-Problem nicht.

Es funktioniert nun! :)

Danke für eure Hilfe!
 
Du kannst auch die insertWithOnConflict() Methode nehmen und da eben als Parameter CONFLICT_IGNORE angeben, dann dürften die Constraint-Warnungen verschwinden.
 
Zurück
Oben