Search code examples
androidsqliteandroid-sqlite

SQLite database UPDATE or INSERT not work


I want to update my database like this: if row exists update it and if row doesn't exist add a new one. In TABLE_MAP_MARKER insert is working but update is not working and in TABLE_MAP_MARKER_INFO in general both, update and insert, don't work. Where is my mistake? Please help me!

Below is my code :

 SQLiteDatabase db = this.getWritableDatabase();
    ContentValues marker_position_values= new ContentValues();
    marker_position_values.put(KEY_MARKER_LAT, map_marker_lat_value);
    marker_position_values.put(KEY_MARKER_LNG, map_marker_long_value);

    long marker_id_table = db.update(TABLE_MAP_MARKER, marker_position_values, HOME_ID + " = ?", new String[]String.valueOf(home_id)});
    if (marker_id_table == 0) {
        db.insertWithOnConflict(TABLE_MAP_MARKER, null, marker_position_values, SQLiteDatabase.CONFLICT_REPLACE);
    }
    ContentValues unit_values= new ContentValues();
    unit_values.put(HOME_ID, marker_id_table);
    unit_values.put(HOME_TYPE, home_type);      
    unit_values.put(AMOUNT_RENT, amount_rent);

    long unit_id_table = db.update(TABLE_MAP_MARKER_INFO, unit_values, HOME_ID + " = ?", new String[]{String.valueOf(home_id)});
    if (unit_id_table == 0) {
        db.insert WithOnConflict(TABLE_MAP_MARKER_INFO, null, unit_values, SQLiteDatabase.CONFLICT_REPLACE);
    }

Solution

  • Some of the issues

    • There are a number of extraneous spaces in your code such as :-

      • String.value Of(home_id)
      • db.insert With On Conflict
    • For a conflict to occur, a constraint must have been specified (implicitly or explicitly). It's not at all clear that you have defined suitable constraints or even what those should be. (example below assumes constraints)

    • Should there not be a row to update in TABLE_MAP_MARKER then marker_id_table will be 0. As such assuming a successful insert into TABLE_MAP_MARKER then 0 will be used for the HOME_ID column for the attempt to update TABLE_MAP_MARKER_INFO (assuming standard use of an ID column and that it is defined as INTEGER PRIMARY KEY (with or without AUTOINCREMENT)) then an id of 0 will not exist, So no row could be updated. However, an row may then be inserted with a HOME_ID of 0 and then the HOME_ID will be out of sync between the two tables. The fix used in the example was to use the HOME_ID value for _id (i.e. the HOME_ID column) column in the TABLE_MAP_MARKER_INFO update/insert.

    Working example :-

    The following based upon UNIQUE constraints :-

    • For the MAP MARKER table that a combination of latitude and longitude should be UNIQUE
    • For the MAP MARKER INFO table that a combination of house type and rent should be UNIQUE (unlikely but what else would be).

    Then the tables could be created using the equivalent of :-

    CREATE TABLE IF NOT EXISTS map_marker(_id INTEGER PRIMARY KEY,map_marker_lat INTEGER,map_marker_lng INTEGER, UNIQUE(map_marker_lat,map_marker_lng));
    CREATE TABLE IF NOT EXISTS map_marker_info(_id INTEGER PRIMARY KEY,home_type TEXT,amount_rent REAL, UNIQUE(HOME_TYPE,AMOUNT_RENT));
    

    Thus an explicit UNIQUE constraint is placed on the map_marker's map_marker_lat along with the map_marker_lng column. So both values in combination must be unique otherwise a conflict is raised. So 100,110 along with 100,120 would be fine but a second 100,110 would result in a conflict.

    Additionally due to PRIMARY KEY the _id column has an implicit unique constraint (as it's INTEGER PRIMARY KEY then it must also be a integer value).

    So with the DatabaseHelper class being (a guess as what you might have, including the addMarkerAndMarkerInfo method that is based upon your code (corrections applied and loggin added - see comments/commented out lines)):-

    public class DatabaseHelper extends SQLiteOpenHelper {
    
        public static final String DBNAME = "marker";
        public static final int DBVERSION = 1;
    
        public static final String TABLE_MAP_MARKER = "map_marker";
        public static final String TABLE_MAP_MARKER_INFO = "map_marker_info";
        public static final String HOME_ID = BaseColumns._ID;
    
        public static final String KEY_MARKER_LAT = "map_marker_lat";
        public static final String KEY_MARKER_LNG = "map_marker_lng";
    
        public static final String HOME_TYPE = "home_type";
        public static final String AMOUNT_RENT = "amount_rent";
    
        public DatabaseHelper(Context context) {
            super(context, DBNAME, null, DBVERSION);
        }
    
        @Override
        public void onCreate(SQLiteDatabase db) {
            String crtmm = "CREATE TABLE IF NOT EXISTS " + TABLE_MAP_MARKER + "(" +
                    HOME_ID + " INTEGER PRIMARY KEY, " +
                    KEY_MARKER_LAT + " INTEGER, " +
                    KEY_MARKER_LNG + " INTEGER, " +
                    " UNIQUE(" +
                    KEY_MARKER_LAT + "," +
                    KEY_MARKER_LNG +
                            ")" +
                    ")";
            String crtmmi = "CREATE TABLE IF NOT EXISTS " + TABLE_MAP_MARKER_INFO + "(" +
                    HOME_ID + " INTEGER PRIMARY KEY, " +
                    HOME_TYPE + " TEXT," +
                    AMOUNT_RENT + " REAL," +
                    " UNIQUE(" +
                    HOME_TYPE + ", " +
                    AMOUNT_RENT +
                    ")" +
                    ")";
            db.execSQL(crtmm);
            db.execSQL(crtmmi);
        }
    
        @Override
        public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
    
        }
    
        public void addMarkerAndMarkerInfo(long home_id,int map_marker_lat_value, int map_marker_long_value, String home_type, double amount_rent, String attempt) {
    
            String TAG = "AMAMI-" + attempt;
            SQLiteDatabase db = this.getWritableDatabase();
            ContentValues marker_position_values= new ContentValues();
            marker_position_values.put(KEY_MARKER_LAT, map_marker_lat_value);
            marker_position_values.put(KEY_MARKER_LNG, map_marker_long_value);
    
            Log.d(TAG,"Attempting Update of MAP MARKER TABLE.");
            long marker_id_table = db.update(TABLE_MAP_MARKER, marker_position_values, HOME_ID + " = ?", new String[]{String.valueOf(home_id)});
            if (marker_id_table == 0) {
                Log.d(TAG,String.valueOf(marker_id_table) + " rows Updated for MAP MARKER TABLE, attempting insert");
                //long insertid = db.insertWithOnConflict(TABLE_MAP_MARKER, null, marker_position_values, SQLiteDatabase.CONFLICT_REPLACE);
                long insertid = db.insertWithOnConflict(TABLE_MAP_MARKER, null, marker_position_values, SQLiteDatabase.CONFLICT_IGNORE);
                //long insertid = db.insert(TABLE_MAP_MARKER, null, marker_position_values); //<<<< used to check what conflicts occur
                if (insertid < 0) {
                    Log.d(TAG,"No row inserted into MAP MARKER TABLE.");
                } else {
                    Log.d(TAG,"Row inserted into MAP MARKER TABLE.");
                }
            } else {
                Log.d(TAG,"Update of MARKER TABLE Successful (" + String.valueOf(marker_id_table) + " rows updated.)");
            }
    
            ContentValues unit_values= new ContentValues();
            //unit_values.put(HOME_ID, marker_id_table); ????????
            unit_values.put(HOME_ID,home_id);
            unit_values.put(HOME_TYPE, home_type);
            unit_values.put(AMOUNT_RENT, amount_rent);
    
            Log.d(TAG,"Attempting Update of MAP MARKER INFO TABLE.");
            long unit_id_table = db.update(TABLE_MAP_MARKER_INFO, unit_values, HOME_ID + " = ?", new String[]{String.valueOf(home_id)});
            if (unit_id_table == 0) {
                Log.d(TAG,String.valueOf(unit_id_table) + " rows Updated for MAP MARKER INFO TABLE, attempting insert");
                long insertid = db.insertWithOnConflict(TABLE_MAP_MARKER_INFO, null, unit_values, SQLiteDatabase.CONFLICT_IGNORE);
                //long insertid = db.insertWithOnConflict(TABLE_MAP_MARKER_INFO, null, unit_values, SQLiteDatabase.CONFLICT_REPLACE);
                //long insertid = db.insert(TABLE_MAP_MARKER_INFO, null, unit_values); //<<<< used to check what conflicts occur
                if (insertid < 0) {
                    Log.d(TAG,"No row inserted into MAP MARKER INFO TABLE");
                } else {
                    Log.d(TAG,"Row inserted into MAP MARKER INFO TABLE.");
                }
            }  else {
                Log.d(TAG,"Update of MARKER INFO TABLE Successful (" + String.valueOf(unit_id_table) + " rows updated.)");
            }
        }
    }
    
    • Note CONFLICT_REPLACE replaced with CONFLICT_IGNORE (really replace a duplicate?)

    Results

    Then Invoking the above using (deletes any existing rows and attempts to add 4 rows):-

        DatabaseHelper mDBHlp = new DatabaseHelper(this);
        mDBHlp.getWritableDatabase().delete(DatabaseHelper.TABLE_MAP_MARKER,null,null);
        mDBHlp.getWritableDatabase().delete(DatabaseHelper.TABLE_MAP_MARKER_INFO,null,null);
    
        mDBHlp.addMarkerAndMarkerInfo(1,100,100,"House",45.64,"Attempt 1");
        mDBHlp.addMarkerAndMarkerInfo(2,150,150,"House",65.64,"Attempt 2");
        // Duplicate
        mDBHlp.addMarkerAndMarkerInfo(3,100,100,"House",45.64,"Attempt 3");
        // Another duplicate
        mDBHlp.addMarkerAndMarkerInfo(1,100,100,"House",45.64,"Attempt 4");
    

    results in :-

    09-04 22:47:16.459 1917-1917/? D/AMAMI-Attempt 1: Attempting Update of MAP MARKER TABLE.
        0 rows Updated for MAP MARKER TABLE, attempting insert
    09-04 22:47:16.463 1917-1917/? D/AMAMI-Attempt 1: Row inserted into MAP MARKER TABLE.
        Attempting Update of MAP MARKER INFO TABLE.
        0 rows Updated for MAP MARKER INFO TABLE, attempting insert
    09-04 22:47:16.467 1917-1917/? D/AMAMI-Attempt 1: Row inserted into MAP MARKER INFO TABLE.
    
    
    09-04 22:47:16.467 1917-1917/? D/AMAMI-Attempt 2: Attempting Update of MAP MARKER TABLE.
        0 rows Updated for MAP MARKER TABLE, attempting insert
    09-04 22:47:16.471 1917-1917/? D/AMAMI-Attempt 2: Row inserted into MAP MARKER TABLE.
        Attempting Update of MAP MARKER INFO TABLE.
        0 rows Updated for MAP MARKER INFO TABLE, attempting insert
    09-04 22:47:16.475 1917-1917/? D/AMAMI-Attempt 2: Row inserted into MAP MARKER INFO TABLE.
    
    
    09-04 22:47:16.475 1917-1917/? D/AMAMI-Attempt 3: Attempting Update of MAP MARKER TABLE.
        0 rows Updated for MAP MARKER TABLE, attempting insert
        No row inserted into MAP MARKER TABLE.
        Attempting Update of MAP MARKER INFO TABLE.
        0 rows Updated for MAP MARKER INFO TABLE, attempting insert
        No row inserted into MAP MARKER INFO TABLE
    
    
    09-04 22:47:16.475 1917-1917/? D/AMAMI-Attempt 4: Attempting Update of MAP MARKER TABLE.
    09-04 22:47:16.479 1917-1917/? D/AMAMI-Attempt 4: Update of MARKER TABLE Successful (1 rows updated.)
        Attempting Update of MAP MARKER INFO TABLE.
    09-04 22:47:16.483 1917-1917/? D/AMAMI-Attempt 4: Update of MARKER INFO TABLE Successful (1 rows updated.)
    

    i.e.

    • 1 and 2 have added rows as nothing to update.
    • 3 has done nothing as no id 3 but duplicate data.
    • 4 has updated the rows as they exist.

    Supplementary Issue

    It would also appear that there may be no need for the two tables, as there seems to be a 1-1 relationship between the two tables. Therefore it may be that a single table could have all the columns (latitude, longitude, type and rent).

    Additional

    Adding the method logAllRows (as follows) and calling this at the end of each update/insert. Allows you to see the actual data.

    private void logAllRows(String tablename, String TAG) {
        SQLiteDatabase db = this.getWritableDatabase();
        StringBuilder sb = new StringBuilder();
        Cursor csr = db.query(tablename,null,null,null,null,null,null);
        while (csr.moveToNext()) {
            sb.append("\nRow # = ").append(String.valueOf(csr.getPosition() + 1));
            for (int i=0; i < csr.getColumnCount(); i++) {
                sb.append("\n\tColumn is ").append(csr.getColumnName(i)).append(" Value is ");
                int columntype = csr.getType(i);
                switch (columntype) {
                    case Cursor.FIELD_TYPE_NULL:
                        sb.append("NULL");
                        break;
                    case Cursor.FIELD_TYPE_FLOAT:
                        sb.append(String.valueOf(csr.getDouble(i)));
                        break;
                    case Cursor.FIELD_TYPE_INTEGER:
                        sb.append(String.valueOf(csr.getInt(i)));
                        break;
                    case Cursor.FIELD_TYPE_STRING:
                        sb.append(csr.getString(i));
                        break;
                    case Cursor.FIELD_TYPE_BLOB:
                        sb.append("BLOB");
                        break;
                }
            }
        }
        csr.close();
        Log.d(TAG,sb.toString());
    }
    

    Results when using logAllRows

    09-05 02:49:56.875 3016-3016/? D/AMAMI-Attempt 1: Attempting Update of MAP MARKER TABLE.
    09-05 02:49:56.879 3016-3016/? D/AMAMI-Attempt 1: 0 rows Updated for MAP MARKER TABLE, attempting insert
        Row inserted into MAP MARKER TABLE. ID = 1
         Table is map_marker Row # = 1
            Column is _id Value is 1
            Column is map_marker_lat Value is 100
            Column is map_marker_lng Value is 100
        Attempting Update of MAP MARKER INFO TABLE.
        0 rows Updated for MAP MARKER INFO TABLE, attempting insert
    09-05 02:49:56.887 3016-3016/? D/AMAMI-Attempt 1: Row inserted into MAP MARKER INFO TABLE. ID = 1
         Table is map_marker_info Row # = 1
            Column is _id Value is 1
            Column is home_type Value is House
            Column is amount_rent Value is 45.64
    
    
    09-05 02:49:56.887 3016-3016/? D/AMAMI-Attempt 2: Attempting Update of MAP MARKER TABLE.
        0 rows Updated for MAP MARKER TABLE, attempting insert
    09-05 02:49:56.903 3016-3016/? D/AMAMI-Attempt 2: Row inserted into MAP MARKER TABLE. ID = 2
         Table is map_marker Row # = 1
            Column is _id Value is 1
            Column is map_marker_lat Value is 100
            Column is map_marker_lng Value is 100
         Table is map_marker Row # = 2
            Column is _id Value is 2
            Column is map_marker_lat Value is 150
            Column is map_marker_lng Value is 150
        Attempting Update of MAP MARKER INFO TABLE.
        0 rows Updated for MAP MARKER INFO TABLE, attempting insert
    09-05 02:49:56.907 3016-3016/? D/AMAMI-Attempt 2: Row inserted into MAP MARKER INFO TABLE. ID = 2
         Table is map_marker_info Row # = 1
            Column is _id Value is 1
            Column is home_type Value is House
            Column is amount_rent Value is 45.64
         Table is map_marker_info Row # = 2
            Column is _id Value is 2
            Column is home_type Value is House
            Column is amount_rent Value is 65.64
    
    
    09-05 02:49:56.907 3016-3016/? D/AMAMI-Attempt 3: Attempting Update of MAP MARKER TABLE.
        0 rows Updated for MAP MARKER TABLE, attempting insert
        No row inserted into MAP MARKER TABLE.
         Table is map_marker Row # = 1
            Column is _id Value is 1
            Column is map_marker_lat Value is 100
            Column is map_marker_lng Value is 100
         Table is map_marker Row # = 2
            Column is _id Value is 2
            Column is map_marker_lat Value is 150
            Column is map_marker_lng Value is 150
        Attempting Update of MAP MARKER INFO TABLE.
    09-05 02:49:56.911 3016-3016/? D/AMAMI-Attempt 3: 0 rows Updated for MAP MARKER INFO TABLE, attempting insert
        No row inserted into MAP MARKER INFO TABLE
         Table is map_marker_info Row # = 1
            Column is _id Value is 1
            Column is home_type Value is House
            Column is amount_rent Value is 45.64
         Table is map_marker_info Row # = 2
            Column is _id Value is 2
            Column is home_type Value is House
            Column is amount_rent Value is 65.64
    
    
    09-05 02:49:56.911 3016-3016/? D/AMAMI-Attempt 4: Attempting Update of MAP MARKER TABLE.
    09-05 02:49:56.915 3016-3016/? D/AMAMI-Attempt 4: Update of MARKER TABLE Successful (1 rows updated.)
         Table is map_marker Row # = 1
            Column is _id Value is 1
            Column is map_marker_lat Value is 100
            Column is map_marker_lng Value is 100
         Table is map_marker Row # = 2
            Column is _id Value is 2
            Column is map_marker_lat Value is 150
            Column is map_marker_lng Value is 150
        Attempting Update of MAP MARKER INFO TABLE.
    09-05 02:49:56.919 3016-3016/? D/AMAMI-Attempt 4: Update of MARKER INFO TABLE Successful (1 rows updated.)
         Table is map_marker_info Row # = 1
            Column is _id Value is 1
            Column is home_type Value is House
            Column is amount_rent Value is 45.64
         Table is map_marker_info Row # = 2
            Column is _id Value is 2
            Column is home_type Value is House
            Column is amount_rent Value is 65.64