是否可以(模拟?)在Sqlite中对复合PK进行自动增量?
根据SQLite,获取自动递增列的唯一方法是在主键上 我需要一个复合主键,但我也需要自动递增。有没有一种方法可以在SQLite中实现这两个目标 我在PostgreSQL中编写的表格的相关部分:是否可以(模拟?)在Sqlite中对复合PK进行自动增量?,sqlite,auto-increment,compound-key,Sqlite,Auto Increment,Compound Key,根据SQLite,获取自动递增列的唯一方法是在主键上 我需要一个复合主键,但我也需要自动递增。有没有一种方法可以在SQLite中实现这两个目标 我在PostgreSQL中编写的表格的相关部分: CREATE TABLE tstage ( id SERIAL NOT NULL, node INT REFERENCES nodes(id) NOT NULL, PRIMARY KEY (id,node),
CREATE TABLE tstage (
id SERIAL NOT NULL,
node INT REFERENCES nodes(id) NOT NULL,
PRIMARY KEY (id,node),
-- ... other columns
);
此要求的原因是,所有节点最终都会将其数据转储到一个集中式节点,在该节点中,如果使用单列PK,则会发生冲突。文档是正确的。 但是,可以在触发器中重新实现自动增量逻辑:
CREATE TABLE tstage (
id INT, -- allow NULL to be handled by the trigger
node INT REFERENCES nodes(id) NOT NULL,
PRIMARY KEY (id, node)
);
CREATE TABLE tstage_sequence (
seq INTEGER NOT NULL
);
INSERT INTO tstage_sequence VALUES(0);
CREATE TRIGGER tstage_id_autoinc
AFTER INSERT ON tstage
FOR EACH ROW
WHEN NEW.id IS NULL
BEGIN
UPDATE tstage_sequence
SET seq = seq + 1;
UPDATE tstage
SET id = (SELECT seq
FROM tstage_sequence)
WHERE rowid = NEW.rowid;
END;
(如果有多个表,请使用带有表名的通用
my_序列表。)文档正确。
但是,可以在触发器中重新实现自动增量逻辑:
CREATE TABLE tstage (
id INT, -- allow NULL to be handled by the trigger
node INT REFERENCES nodes(id) NOT NULL,
PRIMARY KEY (id, node)
);
CREATE TABLE tstage_sequence (
seq INTEGER NOT NULL
);
INSERT INTO tstage_sequence VALUES(0);
CREATE TRIGGER tstage_id_autoinc
AFTER INSERT ON tstage
FOR EACH ROW
WHEN NEW.id IS NULL
BEGIN
UPDATE tstage_sequence
SET seq = seq + 1;
UPDATE tstage
SET id = (SELECT seq
FROM tstage_sequence)
WHERE rowid = NEW.rowid;
END;
(如果有多个表,则使用带有表名的公共my_序列表。)触发器可以工作,但很复杂。更简单地说,您可以避免使用串行ID。一种方法是,你可以使用。不幸的是,我找不到让SQLite默认为您生成GUID的方法,因此您必须在应用程序中生成GUID。也没有GUID类型,但可以将其存储为字符串或字符串
或者,您的其他列中可能有一些内容可以作为合适的键。如果您知道插入不会比选择的时间戳格式()的解析更频繁,那么(节点,时间戳列)
可能是一个好的主键
或者,您可以使用SQLite的AUTOINCREMENT
,但可以通过SQLite\u sequence
表,这样生成的序列就不会发生冲突。由于rowid
是一个64位的数字,您可以通过为每个节点生成一个唯一的32位数字(IP地址是一个方便的,可能是唯一的32位数字)并将其左移32位,或者等效地将其乘以4294967296来实现。因此,64位的rowid
实际上成为两个串联的32位数字,节点ID,记录ID
,保证不会发生冲突,除非一个节点生成超过40亿条记录。触发器工作,但很复杂。更简单地说,您可以避免使用串行ID。一种方法是,你可以使用。不幸的是,我找不到让SQLite默认为您生成GUID的方法,因此您必须在应用程序中生成GUID。也没有GUID类型,但可以将其存储为字符串或字符串
或者,您的其他列中可能有一些内容可以作为合适的键。如果您知道插入不会比选择的时间戳格式()的解析更频繁,那么(节点,时间戳列)
可能是一个好的主键
或者,您可以使用SQLite的AUTOINCREMENT
,但可以通过SQLite\u sequence
表,这样生成的序列就不会发生冲突。由于rowid
是一个64位的数字,您可以通过为每个节点生成一个唯一的32位数字(IP地址是一个方便的,可能是唯一的32位数字)并将其左移32位,或者等效地将其乘以4294967296来实现。因此,64位的rowid
实际上变成了两个串联的32位数字,NODE\u ID,RECORD\u ID
,保证不会冲突,除非一个节点生成超过40亿条记录。怎么样
假设
- 只需要PK中的唯一性,不需要序列性
- 源表有一个PK
创建带有一个额外列的中心表,节点编号
CREATE TABLE tstage (
node INTEGER NOT NULL,
id INTEGER NOT NULL, <<< or whatever the source table PK is
PRIMARY KEY (node, id)
:
);
不需要在中心表上维护另一个自动递增列,因为nodenumber+sourcetable\u id将始终是唯一的。如何
假设
- 只需要PK中的唯一性,不需要序列性
- 源表有一个PK
创建带有一个额外列的中心表,节点编号
CREATE TABLE tstage (
node INTEGER NOT NULL,
id INTEGER NOT NULL, <<< or whatever the source table PK is
PRIMARY KEY (node, id)
:
);
不需要在中心表上维护另一个自动递增列,因为nodenumber+sourcetable_id将始终是唯一的。如果有索引,则从t选择max(id)非常有效。触发器是否意味着事务,或者我需要在UPDATE tstage\u sequence…
之前显式开始一个事务以防止客户端之间的竞争吗?触发器总是与触发命令在同一个事务中运行。我想我的问题更多的是触发器本身是否是原子的。如果存在争用,UPDATE tstage\u序列
可能触发两次,那么UPDATE tstage
将失败,并在第二个客户端上出现唯一密钥冲突。我希望找到一种使触发器原子化的方法,因此我不必在客户端代码中检查此故障。SQLite事务总是完全序列化的(因为没有并发)。SELECT max(id)FROM t t
在有索引的情况下非常有效。触发器是否意味着事务,或者我需要在UPDATE tstage\u sequence…
之前显式开始一个事务以防止客户端之间的竞争吗?触发器总是与触发命令在同一个事务中运行。我想我的问题更多的是触发器本身是否是原子的。如果存在争用,UPDATE tstage\u序列
可能触发两次,那么UPDATE tstage
将失败,并在第二个客户端上出现唯一密钥冲突。我希望找到一种使触发器原子化的方法,因此我不必在客户端代码中检查此故障。SQLite事务总是完全序列化的(因为没有并发)。(节点,id)
本质上已经是一个GUID。我明白你的意思了——使用某种位图将它们组合成一个db字段。(节点,id)
本质上已经是一个GUID了。我明白你的意思了——使用某种位图将它们组合成一个db字段。