这是否意味着,对于无行 ID,我必须指定我自己的 Primary
插入时的键值?
是的(尽管按照下面的一些努力或限制可能不会),就好像你尝试了:-
CREATE TABLE IF NOT EXISTS table001 (col1 INTEGER, col2 INTEGER) WITHOUT ROWID;
然后你会得到一些类似的东西:-
SQLiteManager: Likely SQL syntax error: CREATE TABLE IF NOT EXISTS table001 (col1 INTEGER, col2 INTEGER) WITHOUT ROWID; [ PRIMARY KEY missing on table table001 ]
Exception Name: NS_ERROR_FAILURE
Exception Message: Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [mozIStorageConnection.createStatement]
所以你需要有一个 PRIMARY KEY 并且 SQLite 不会为你提供一个值,因为你已经告诉 SQLite 你不想要那个功能。
将以上内容改为:-
CREATE TABLE IF NOT EXISTS table001 (col1 INTEGER, col2 INTEGER, PRIMARY KEY (col1,col2)) WITHOUT ROWID;
有效。但是,您需要指定值。
以上对于关联表很有用,如果主索引是根据您将引用的列而不是
由rowid,这基本上是插入顺序。当然,对于此类表,您可能不会在不知道列值的情况下插入行。
所以WITHOUT ROWID 表是有用的。
如果你真的想要,你可以很容易地使用“TRIGGER”引入一个自动递增的数字,伴随着一个带有单行/列的表,该表存储最后使用或下一个要使用的数字,但是为什么你会放弃 rowid 只是为了复制无论如何,rowid 为你做了什么。
如果你想要一个唯一的键,另一种选择是使用 CURRENT_TIMESTAMP 作为默认值。但是,您不能进行批量插入,因为插入之间的间隔会导致 UNIQUE 约束冲突。
如果我不使用WithoutRowID,我将有两个主键,
因为 SQLite 管理自己的 RowID 以及我自己的主键
价值。在 1.7GB 的数据库上,使用 WithoutRowID 可以减少
文件中的索引只有 1.3GB,所以 400MB 的差异是相当的
节省大量资金。
请告诉我,我不必提供自己的主键 ID 和
它实际上会提供一个针对主键的唯一 ID,如果它
是一个整数。
当然,您的“我自己的主键值” 不是神奇地生成的,即您知道该值(假设它不仅仅是 rowid 的副本),因此它将用于主键。
有点有趣的是使用 :-
CREATE TABLE IF NOT EXISTS table002 (pk INTEGER PRIMARY KEY, col1 TEXT)
WITHOUT ROWID;
INSERT INTO table002 VALUES
(2,'fred'),
(3,'bert'),
(-100,'alfred'),
('june','mary');
表明使用WITHOUT ROWID 提供了PRIMARY KEY 更大的灵活性,因为它不限于INTEGER,就像rowid 一样,TEXT PRIMARY KEY.....
即上述结果:-
Android 的另一个考虑因素
WITHTOUT ROWID 是在版本 3.8.2 中引入的,某些设备可能没有安装该版本或更高版本,因此 WITHOUT ROWID 甚至可能不是某些 Android 应用程序的选项。
如果你真的想要的例子:-
这是管理您自己的 psuedo_autoincrement 的示例。这不是增加 1,而是根据指定的数量(在本例中为 10)增加。它不完整,因为它没有上限检查/处理。
这是插入 3 行后的结果:-
这是随附的序列表(准备好进行下一次插入,即 _seq 为 31):-
- _incby 是增加的数量(在这种情况下为 10)
- 每次达到 _limit 时,_offset 列将跳转到 1, 2 ...9(允许最大 9 之后)。因此,当偏移量为 1(插入 5000 次后)时,将使用 2, 12 ,22 .....。但是,这尚未实施。
- 我想您可以使用上面的方法来进行“自动减量”,但需要稍作调整。
关键(双关语无意)是TRIGGER:-
CREATE TRIGGER seqtrg_mytable
AFTER INSERT ON mytable
BEGIN
UPDATE my_sequence SET _seq = _seq + _inc_by
WHERE _name = 'mytable';
END
还有 INSERT :-
INSERT INTO mytable VALUES ((SELECT _seq FROM my_sequence) ,'Test001')
这在 Android 上使用以下检查/使用:-
DBHelper.java
public class DBHelper extends SQLiteOpenHelper {
public static final String DBNAME = "weird";
public static final int DBVERSION = 1;
public static final String TBMYSEQ = "my_sequence";
public static final String COL_MYSEQ_NAME = "_name";
public static final String COL_MYSEQ_SEQ = "_seq";
public static final String COL_MYSEQ_INCBY = "_inc_by";
public static final String COL_MYSEQ_OFFSET = "_offset";
public static final String COl_MYSEQ_LIMIT = "_limit";
public static final String TBMYTABLE = "mytable";
public static final String COL_SPECIALIX = "_special_primary_autoinc_index";
public static final String COL_MYVALUE = "myvalue";
public static final int MYTABLE_INCYBY = 10;
public static final int MYTABLE_LIMIT = 50000;
SQLiteDatabase mDB;
public DBHelper(Context context) {
super(context, DBNAME, null, DBVERSION);
mDB = this.getWritableDatabase();
}
@Override
public void onCreate(SQLiteDatabase db) {
String crt_myseq_tbl = "CREATE TABLE IF NOT EXISTS " +
TBMYSEQ + "(" +
COL_MYSEQ_NAME + " TEXT PRIMARY KEY," +
COL_MYSEQ_SEQ + " INTEGER DEFAULT 1, " +
COL_MYSEQ_INCBY + " INTEGER DEFAULT 1, " +
COL_MYSEQ_OFFSET + " INTEGER DEFAULT 0," +
COl_MYSEQ_LIMIT + " INTEGER NOT NULL" +
")";
db.execSQL(crt_myseq_tbl);
String crt_mytable_tbl = "CREATE TABLE IF NOT EXISTS " +
TBMYTABLE + "(" +
COL_SPECIALIX + " TEXT PRIMARY KEY DEFAULT -1," +
COL_MYVALUE + " TEXT" +
")";
db.execSQL(crt_mytable_tbl);
insertMySeqRow(TBMYTABLE,MYTABLE_INCYBY,MYTABLE_LIMIT,db);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
private void insertMySeqRow(String for_table,int incby, int limit, SQLiteDatabase optionaldb) {
ContentValues cv = new ContentValues();
cv.put(COL_MYSEQ_NAME,for_table);
cv.put(COL_MYSEQ_INCBY,incby);
cv.put(COl_MYSEQ_LIMIT,limit);
if (optionaldb == null) {
optionaldb = mDB;
}
optionaldb.insert(TBMYSEQ,null,cv);
String crt_trigger_sql =
"CREATE TRIGGER IF NOT EXISTS seqtrg_" + for_table +
" AFTER INSERT ON " + for_table +
" BEGIN " +
" UPDATE " + TBMYSEQ +
" SET " + COL_MYSEQ_SEQ + " = " +
COL_MYSEQ_SEQ + " + " + COL_MYSEQ_INCBY +
" WHERE " + COL_MYSEQ_NAME + " = '" + for_table +
"';" +
"END";
optionaldb.execSQL(crt_trigger_sql);
}
public void insertMyTableRow(String value) {
String insertsql = "INSERT INTO " +TBMYTABLE +
" VALUES (" +
"(SELECT " + COL_MYSEQ_SEQ + " " +
"FROM " + TBMYSEQ +
") " +
",'" + value + "')";
mDB.execSQL(insertsql);
}
}
MainActivty.java :-
public class MainActivity extends AppCompatActivity {
DBHelper mDBHlpr;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDBHlpr = new DBHelper(this);
mDBHlpr.insertMyTableRow("Test001");
mDBHlpr.insertMyTableRow("Test002");
mDBHlpr.insertMyTableRow("TEST003");
Cursor csr1 = CommonSQLiteUtilities.getAllRowsFromTable(
mDBHlpr.getWritableDatabase(),
DBHelper.TBMYTABLE,
true,
null
);
CommonSQLiteUtilities.logCursorData(csr1);
csr1.close();
Cursor csr2 = CommonSQLiteUtilities.getAllRowsFromTable(
mDBHlpr.getWritableDatabase(),
DBHelper.TBMYSEQ,
true,
null
);
CommonSQLiteUtilities.logCursorData(csr2);
csr2.close();
}
}
输出是:-
04-22 11:57:53.120 2910-2910/? D/SQLITE_CSU: DatabaseList Row 1 Name=main File=/data/data/weird.weirdprimarykey/databases/weird
PRAGMA - sqlite_version = 3.7.11
PRAGMA - user_version = 1
04-22 11:57:53.128 2910-2910/? D/SQLITE_CSU: PRAGMA - encoding = UTF-8
PRAGMA - auto_vacuum = 1
PRAGMA - cache_size = 2000
PRAGMA - foreign_keys = 0
PRAGMA - freelist_count = 0
PRAGMA - ignore_check_constraints = 0
04-22 11:57:53.132 2910-2910/? D/SQLITE_CSU: PRAGMA - journal_mode = persist
PRAGMA - journal_size_limit = 524288
PRAGMA - locking_mode = normal
PRAGMA - max_page_count = 1073741823
PRAGMA - page_count = 7
PRAGMA - page_size = 4096
PRAGMA - recursive_triggers = 0
PRAGMA - reverse_unordered_selects = 0
PRAGMA - secure_delete = 0
04-22 11:57:53.136 2910-2910/? D/SQLITE_CSU: PRAGMA - synchronous = 2
PRAGMA - temp_store = 0
PRAGMA - wal_autocheckpoint = 100
Table Name = android_metadata Created Using = CREATE TABLE android_metadata (locale TEXT)
Table = android_metadata ColumnName = locale ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
Number of Indexes = 0
Number of Foreign Keys = 0
Number of Triggers = 0
Table Name = my_sequence Created Using = CREATE TABLE my_sequence(_name TEXT PRIMARY KEY,_seq INTEGER DEFAULT 1, _inc_by INTEGER DEFAULT 1, _offset INTEGER DEFAULT 0,_limit INTEGER NOT NULL)
Table = my_sequence ColumnName = _name ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 1
Table = my_sequence ColumnName = _seq ColumnType = INTEGER Default Value = 1 PRIMARY KEY SEQUENCE = 0
Table = my_sequence ColumnName = _inc_by ColumnType = INTEGER Default Value = 1 PRIMARY KEY SEQUENCE = 0
Table = my_sequence ColumnName = _offset ColumnType = INTEGER Default Value = 0 PRIMARY KEY SEQUENCE = 0
Table = my_sequence ColumnName = _limit ColumnType = INTEGER Default Value = null PRIMARY KEY SEQUENCE = 0
Number of Indexes = 1
INDEX NAME = sqlite_autoindex_my_sequence_1
Sequence = 0
Unique = true
Index Origin indicator unsupported
Index Partial indicator unsupported
INDEX COLUMN = _name COLUMN ID = 0 SEQUENCE = 0
Number of Foreign Keys = 0
Number of Triggers = 0
Table Name = mytable Created Using = CREATE TABLE mytable(_special_primary_autoinc_index TEXT PRIMARY KEY DEFAULT -1,myvalue TEXT)
04-22 11:57:53.140 2910-2910/? D/SQLITE_CSU: Table = mytable ColumnName = _special_primary_autoinc_index ColumnType = TEXT Default Value = -1 PRIMARY KEY SEQUENCE = 1
Table = mytable ColumnName = myvalue ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
Number of Indexes = 1
INDEX NAME = sqlite_autoindex_mytable_1
Sequence = 0
Unique = true
Index Origin indicator unsupported
Index Partial indicator unsupported
INDEX COLUMN = _special_primary_autoinc_index COLUMN ID = 0 SEQUENCE = 0
Number of Foreign Keys = 0
Number of Triggers = 1
TRIGGER NAME =seqtrg_mytable
SQL = CREATE TRIGGER seqtrg_mytable AFTER INSERT ON mytable BEGIN UPDATE my_sequence SET _seq = _seq + _inc_by WHERE _name = 'mytable';END
Cursor has 3 rows and 2 Columns.
Information for Row 1 offset = 0
For Column _special_primary_autoinc_indexType is STRING value as String is 1 value as long is 1 value as double is 1.0
For Column myvalueType is STRING value as String is Test001 value as long is 0 value as double is 0.0
Information for Row 2 offset = 1
For Column _special_primary_autoinc_indexType is STRING value as String is 11 value as long is 11 value as double is 11.0
For Column myvalueType is STRING value as String is Test002 value as long is 0 value as double is 0.0
Information for Row 3 offset = 2
For Column _special_primary_autoinc_indexType is STRING value as String is 21 value as long is 21 value as double is 21.0
For Column myvalueType is STRING value as String is TEST003 value as long is 0 value as double is 0.0
Cursor has 1 rows and 5 Columns.
Information for Row 1 offset = 0
For Column _nameType is STRING value as String is mytable value as long is 0 value as double is 0.0
For Column _seqType is INTEGER value as String is 31 value as long is 31 value as double is 31.0
For Column _inc_byType is INTEGER value as String is 10 value as long is 10 value as double is 10.0
For Column _offsetType is INTEGER value as String is 0 value as long is 0 value as double is 0.0
For Column _limitType is INTEGER value as String is 50000 value as long is 50000 value as double is 50000.0