sql >> Database >  >> RDS >> SQLite

Android Room - Hoe de automatisch gegenereerde primaire sleutel van de tabel opnieuw in te stellen bij elke app-run

Om de tabellen bij het afsluiten te wissen, wordt de keystarting-index niet gereset, maar begint het waar het was gebleven bij de laatste run.

....

"delete from sqlite_sequence where name='Sequence Action'" Geen fout, maar de index wordt ook niet gereset.

U moet beide alle rijen in de SequenceAction . verwijderen tabel EN verwijder de respectieve rij uit sqlite_sequence.

Dat is wanneer het trefwoord AUTOINCREMENT wordt gebruikt, dan wordt een ander algoritme gebruikt. Dit is in de trant van:-

Zoek de hoogste waarde van ofwel a) de waardeopslag voor de tabel in het sqlite_sequence-nummer en b) de hoogste rowid-waarde

Een alternatief zou zijn om de AUTOINCREMENT . niet te gebruiken trefwoord, in plaats van gewoon ?? INTEGER PRIMARY KEY (waar ?? staat voor de kolomnaam).

Je zou nog steeds een unieke id hebben die een alias is van de rowid kan, maar er is geen garantie dat dit altijd zal toenemen. AUTOINCREMENT garandeert wel een toenemende unieke id, maar het garandeert geen monotoon toenemende unieke rowid.

Bij elke toepassing heb ik deze sleutel nodig om vanaf 0 te beginnen.

SQLite stelt echter de eerste waarde in op 1 en niet op 0.

Het volgende werkt, en zoals je ziet met AUTOINCREMENT (hoewel een beetje een hack):-

DROP TABLE IF EXISTS SequenceAction;
DROP TRIGGER IF EXISTS use_zero_as_first_sequence;
CREATE TABLE IF NOT EXISTS SequenceAction (id INTEGER PRIMARY KEY AUTOINCREMENT, otherdata TEXT);
CREATE TRIGGER IF NOT EXISTS use_zero_as_first_sequence AFTER INSERT ON SequenceAction
    BEGIN 
        UPDATE SequenceAction SET id = id - 1 WHERE id = new.id;
    END
;
INSERT INTO SequenceAction VALUES(null,'TEST1'),(null,'TEST2'),(null,'TEST3');
SELECT * FROM SequenceAction;
-- RESET and RESTART FROM 0
DELETE FROM SequenceAction;
DELETE FROM sqlite_sequence WHERE name = 'SequenceAction';
INSERT INTO SequenceAction VALUES(null,'TEST4'),(null,'TEST5'),(null,'TEST6');
SELECT * FROM SequenceAction
  • De 2 DROP-instructies die alleen nodig zijn om te testen om te verwijderen en opnieuw te definiëren.

Dit resulteert in:-

De eerste vraag die terugkomt:-

en de 2e terugkeer:-

Dus in wezen wil je :-

DELETE FROM SequenceAction;
DELETE FROM sqlite_sequence WHERE name = 'SequenceAction';

En ook de Trigger als je wilt dat de nummering begint bij 0 in plaats van 1.

Als alternatief, als u AUTOINCREMENT heeft afgeschaft, kunt u een licht gewijzigde trigger gebruiken:-

CREATE TRIGGER IF NOT EXISTS use_zero_as_first_sequence 
    AFTER INSERT ON SequenceAction 
    WHEN (SELECT count() FROM SequenceAction) = 1
    BEGIN 
        UPDATE SequenceAction SET id = 0;
    END
;
  • Dit hernummert alleen de allereerste ingevoegde rij (het algoritme voegt dan 1 toe voor volgende invoegingen)

En verwijder dan gewoon alle rijen van alleen de SequenceAction-tabel om de nummering opnieuw in te stellen.

Voorbeeld van kamer:-

Op basis van uw code en het bovenstaande voorbeeld lijkt de volgende methode te werken:-

private void resetSequenceAction() {
    SQLiteDatabase dbx;
    String sqlite_sequence_table = "sqlite_sequence";
    long initial_sacount;
    long post_sacount;
    long initial_ssn =0;
    long post_ssn = 0;
    Cursor csr;

    /*
        Need to Create Database and table if it doesn't exist
     */
    File f = this.getDatabasePath(TestDatabase.DBNAME);
    if (!f.exists()) {
        File d = new File(this.getDatabasePath(TestDatabase.DBNAME).getParent());
        d.mkdirs();
        dbx = SQLiteDatabase.openOrCreateDatabase(f,null);
        String crtsql = "CREATE TABLE IF NOT EXISTS " + SequenceAction.tablename + "(" +
                SequenceAction.id_column + " INTEGER PRIMARY KEY AUTOINCREMENT," +
                SequenceAction.actionType_column + " TEXT," +
                SequenceAction.extraInfo_column + " TEXT" +
                ")";
        dbx.execSQL(crtsql);
        /*
           Might as well create the Trigger as well
         */
        String triggerSql = "CREATE TRIGGER IF NOT EXISTS user_zero_as_first_rowid AFTER INSERT ON " +
                SequenceAction.tablename +
                " BEGIN " +
                " UPDATE " + SequenceAction.tablename +
                " SET " +
                SequenceAction.id_column + " = " + SequenceAction.id_column + " - 1 " +
                " WHERE " + SequenceAction.id_column + " = new." + SequenceAction.id_column + ";" +
                " END ";
        dbx.execSQL(triggerSql);

    } else {
        dbx = SQLiteDatabase.openDatabase(this.getDatabasePath(TestDatabase.DBNAME).getPath(),null, Context.MODE_PRIVATE);
    }

    /*
        Add trigger to set id's to 1 less than they were set to
     */
    initial_sacount = DatabaseUtils.queryNumEntries(dbx,SequenceAction.tablename);
    /*
        Delete all the rows at startup
     */
    String deleteAllSequenceIdRowsSql = "DELETE FROM " + SequenceAction.tablename;
    dbx.execSQL(deleteAllSequenceIdRowsSql);
    post_sacount = DatabaseUtils.queryNumEntries(dbx,SequenceAction.tablename);
    /*
        delete the sequence row from the sqlite_sequence table
     */
    csr = dbx.query(sqlite_sequence_table,
            new String[]{"seq"},"name=?",
            new String[]{SequenceAction.tablename},
            null,null,null
    );
    if (csr.moveToFirst()) {
        initial_ssn = csr.getLong(csr.getColumnIndex("seq"));
    }
    String deleteSqlLiteSequenceRow = "DELETE FROM " +
            sqlite_sequence_table +
            " WHERE name = '" + SequenceAction.tablename + "'";
    dbx.execSQL(deleteSqlLiteSequenceRow);
    csr = dbx.query(
            sqlite_sequence_table,
            new String[]{"seq"},
            "name=?",
            new String[]{SequenceAction.tablename},
            null,null,null
    );
    if (csr.moveToFirst()) {
        post_ssn = csr.getLong(csr.getColumnIndex("seq"));
    }
    csr.close();
    Log.d("SEQACTSTATS",
            "Initial Rowcount=" + String.valueOf(initial_sacount) +
                    " Initial Seq#=" + String.valueOf(initial_ssn) +
                    " Post Delete Rowcount =" + String.valueOf(post_sacount) +
                    " Post Delete Seq#=" + String.valueOf(post_ssn)
    );
    dbx.close();
}

Resultaat van een eerste run (d.w.z. er bestaat geen DB):-

D/SEQACTSTATS: Initial Rowcount=0 Initial Seq#=0 Post Delete Rowcount =0 Post Delete Seq#=0

Van een volgende run (nadat 40 rijen zijn toegevoegd):-

D/SEQACTSTATS: Initial Rowcount=40 Initial Seq#=40 Post Delete Rowcount =0 Post Delete Seq#=0

Een methode toevoegen om alle rijen weer te geven, volgens:-

private void listAllRows() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            salist = mTestDB.SequenceActionDaoAccess().getAll();
            getSequenceActionList(salist);
        }
    }).start();
}

Samen met:-

@Override
public void getSequenceActionList(List<SequenceAction> sequenceActionList) {
    for (SequenceAction sa: sequenceActionList) {
        Log.d("SA","ID=" + String.valueOf(sa.getSequenceId()) + " AT=" + sa.getActionType() + " EI=" + sa.getExtraInfo());
    }
}

Resultaten in (eerste rij is ID=0 AT=X0 EI=Y0 d.w.z. de ID kolom van de eerste rij is 0 ):-

06-17 02:56:47.867 5526-5554/rt_mjt.roomtest D/SA: ID=0 AT=X0 EI=Y0
    ID=1 AT=X0 EI=Y0
    ID=2 AT=X0 EI=Y0
    ID=3 AT=X0 EI=Y0
    ID=4 AT=X1 EI=Y1
    ID=5 AT=X1 EI=Y1
    ID=6 AT=X1 EI=Y1
    ID=7 AT=X1 EI=Y1
06-17 02:56:47.868 5526-5554/rt_mjt.roomtest D/SA: ID=8 AT=X2 EI=Y2
    ID=9 AT=X2 EI=Y2
    ID=10 AT=X2 EI=Y2
    ID=11 AT=X2 EI=Y2
    ID=12 AT=X3 EI=Y3
    ID=13 AT=X3 EI=Y3
    ID=14 AT=X3 EI=Y3
    ID=15 AT=X3 EI=Y3
    ID=16 AT=X4 EI=Y4
06-17 02:56:47.869 5526-5554/rt_mjt.roomtest D/SA: ID=17 AT=X4 EI=Y4
    ID=18 AT=X4 EI=Y4
    ID=19 AT=X4 EI=Y4
    ID=20 AT=X5 EI=Y5
    ID=21 AT=X5 EI=Y5
    ID=22 AT=X5 EI=Y5
    ID=23 AT=X5 EI=Y5
    ID=24 AT=X6 EI=Y6
    ID=25 AT=X6 EI=Y6
    ID=26 AT=X6 EI=Y6
    ID=27 AT=X6 EI=Y6
06-17 02:56:47.870 5526-5554/rt_mjt.roomtest D/SA: ID=28 AT=X7 EI=Y7
    ID=29 AT=X7 EI=Y7
    ID=30 AT=X7 EI=Y7
    ID=31 AT=X7 EI=Y7
    ID=32 AT=X8 EI=Y8
    ID=33 AT=X8 EI=Y8
    ID=34 AT=X8 EI=Y8
    ID=35 AT=X8 EI=Y8
    ID=36 AT=X9 EI=Y9
    ID=37 AT=X9 EI=Y9
    ID=38 AT=X9 EI=Y9
    ID=39 AT=X9 EI=Y9
  • Opmerkingresultaten kunnen raar zijn omdat er meerdere threads worden uitgevoerd zonder controle/sequencing.

De addSomeData gebruikte methode zijn:-

private void addSomeData() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            SequenceAction sa = new SequenceAction();
            for (int i=0; i < 10; i++) {
                sa.setSequenceId(0);
                sa.setActionType("X" + String.valueOf(i));
                sa.setExtraInfo("Y" + String.valueOf(i));
                mTestDB.SequenceActionDaoAccess().insertSingleRow(sa);
            }
        }
    }) .start();
}

Toevoeging bij opmerkingen:-

"Ik geloof dat je voor Room binnen moet zijn..." - bedoel je het uitvoeren van de SQL die de actieve index wist voordat de Roomdatabase wordt geïnstantieerd? - goh

niet noodzakelijk, maar voordat Room de database opent die is voordat u er iets mee probeert te doen. Heb aanroepcode toegevoegd (in Overidden activiteiten onStart() methode) met wat Room Db-toegang om addSomeData onmiddellijk daarna aan te roepen. –MikeT

Hier is een voorbeeld van het aanroepen van de resetSequenceAction-methode nadat de RoomDatabase is geïnstantieerd, maar voordat deze wordt gebruikt om de database te openen/openen (addSomeData opent de reeds geïnstantieerde database en voegt 10 rijen in):-

@Override
protected void onStart() {
    super.onStart();
    mTestDB = Room.databaseBuilder(this,TestDatabase.class,TestDatabase.DBNAME).build(); //<<<< Room DB instantiated
    resetSequenceAction(); //<<<< reset the sequence (adding trigger if needed)
    addSomeData(); // This will be the first access open
    addSomeData();
    addSomeData();
    addSomeData();
    listAllRows();


  1. Hoe parallelle plannen opstarten - Deel 5

  2. MySQL - tel het totale aantal rijen in php

  3. Hoe een externe sleutelbeperking in SQL te verwijderen?

  4. DATEDIFF() Voorbeelden in SQL Server