SQLite
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> SQLite

Android Room - Cách đặt lại khóa chính của bảng được tạo tự động trên mỗi lần chạy ứng dụng

Để xóa các bảng khi thoát nhưng, thao tác này không đặt lại chỉ mục bắt đầu từ khóa, thay vào đó, nó bắt đầu từ nơi nó đã dừng lại trong lần chạy cuối cùng.

....

"delete from sqlite_sequence where name ='Sequence Action'" Không có lỗi nhưng chỉ mục cũng không được đặt lại.

Bạn phải xóa cả hai hàng trong SequenceAction bảng VÀ xóa hàng tương ứng khỏi sqlite_sequence.

Đó là khi từ khóa AUTOINCREMENT được sử dụng thì một thuật toán khác sẽ được sử dụng. Đây là dòng của:-

Tìm giá trị cao nhất của một trong hai- a) giá trị lưu trữ cho bảng trong số sqlite_sequence và- b) giá trị rowid cao nhất

Một giải pháp thay thế là không sử dụng AUTOINCREMENT từ khóa, thay vì chỉ có ?? INTEGER PRIMARY KEY (ở đâu ?? đại diện cho tên cột).

Bạn vẫn sẽ có một id duy nhất là bí danh của rowid coulmn, nhưng không có gì đảm bảo rằng nó sẽ luôn tăng. AUTOINCREMENT đảm bảo id duy nhất ngày càng tăng, nhưng nó không đảm bảo rowid duy nhất tăng một cách đơn điệu.

Trên mỗi lần chạy ứng dụng, tôi cần khóa này bắt đầu từ 0.

Tuy nhiên, SQLite sẽ đặt giá trị đầu tiên thành 1 chứ không phải 0.

Những điều sau đây hoạt động và như bạn thấy với AUTOINCREMENT (mặc dù có một chút 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
  • 2 câu lệnh DROP chỉ bắt buộc để thử nghiệm xóa và xác định lại.

Điều này dẫn đến:-

Truy vấn đầu tiên trả về:-

và lần quay lại thứ 2:-

Vì vậy, về bản chất bạn muốn :-

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

Và cả Trình kích hoạt nếu bạn muốn đánh số bắt đầu từ 0 thay vì 1.

Ngoài ra, nếu bạn không sử dụng AUTOINCREMENT thì bạn có thể sử dụng một Trigger đã thay đổi một chút:-

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
;
  • Điều này chỉ đánh số lại hàng được chèn đầu tiên (sau đó thuật toán thêm 1 lần cho các lần chèn tiếp theo)

Và sau đó chỉ cần xóa tất cả các hàng khỏi bảng SequenceAction, để đặt lại việc đánh số.

Ví dụ sử dụng Room:-

Dựa trên mã của bạn cùng với ví dụ ở trên, phương pháp sau có vẻ hoạt động:-

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();
}

Kết quả từ lần chạy đầu tiên (tức là không tồn tại DB):-

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

Từ lần chạy tiếp theo (sau khi 40 hàng đã được thêm vào):-

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

Thêm một phương thức để liệt kê tất cả các hàng, như sau:-

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

Cùng với:-

@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());
    }
}

Kết quả trong (hàng đầu tiên là ID=0 AT=X0 EI=Y0 tức là ID cột của hàng đầu tiên là 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
  • Kết quả ghi chú có thể lạ do nhiều chuỗi chạy mà không có sự kiểm soát / sắp xếp theo trình tự.

addSomeData phương pháp được sử dụng là:-

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();
}

Nhận xét bổ sung:-

"Tôi tin rằng bạn phải vào trước Room ..." - ý bạn là thực thi SQL xóa chỉ mục đang chạy trước khi khởi tạo Roomdatabase? - con ma cà rồng

không nhất thiết nhưng trước khi Room Mở cơ sở dữ liệu trước khi bạn cố gắng làm bất cứ điều gì với nó. –MikeT

Đây là một ví dụ về việc gọi phương thức resetSequenceAction sau khi RoomDatabase đã được khởi tạo, nhưng trước khi nó được sử dụng để truy cập / mở cơ sở dữ liệu (addSomeData mở Cơ sở dữ liệu đã được khởi tạo và chèn 10 hàng):-

@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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Đặt hàng SQLite theo ngày1530019888000

  2. Cách cài đặt trình duyệt SQLite và SQLite trong Ubuntu

  3. Phương thức onUpgrade có bao giờ được gọi không?

  4. LỖI:Không thể đọc hàng 0, cột -1 từ CursorWindow. Đảm bảo Con trỏ được khởi tạo chính xác trước khi truy cập dữ liệu

  5. So sánh các ngày được lưu trữ dưới dạng chuỗi sử dụng Datetime