SQLite多列主键约束与数据集群存储技术问询
首先得揪出你遇到的核心问题——你认为ConditionCode, VitalSignCode, ReportId, EvtDateTime, Basis的组合是唯一的,但插入时报错说明旧库确实存在该组合重复的行,而你之前用来排查重复的查询有个关键小错误:
你写的排查语句里分组列用了EventDateTime,但你的表字段名是EvtDateTime(少了个e)!这直接导致分组逻辑完全错误,自然查不到重复数据。修正后的查询应该是:
SELECT * FROM ( SELECT MIN(ROWID) as Keep, MAX(ROWID) as Rmove, COUNT(ROWID) as Fltr FROM VSReports GROUP BY ConditionCode, VitalSignCode, ReportId, EvtDateTime, Basis ) as InnerQ WHERE Fltr > 1 LIMIT 10;
跑这个修正后的查询,你就能找到真正的重复行了。
回到你的核心需求:不需要额外添加UnqId列,就能实现按指定顺序集群存储数据,只要解决好组合主键的唯一性问题就行,具体步骤如下:
1. 先清理旧库中的重复数据
既然组合主键冲突,说明旧库中存在同一ConditionCode, VitalSignCode, ReportId, EvtDateTime, Basis组合的多行数据。你需要先处理这些重复:
- 如果这些重复是无效数据(比如重复录入),可以保留其中一行(比如保留
ROWID最大的那一行):-- 删除重复行,仅保留每个组合中ROWID最大的记录 DELETE FROM VSReports WHERE ROWID NOT IN ( SELECT MAX(ROWID) FROM VSReports GROUP BY ConditionCode, VitalSignCode, ReportId, EvtDateTime, Basis ); - 如果重复行的其他字段(比如
VSValue)有差异,你需要从业务层面判断如何合并这些数据。
2. 重新创建目标表并正确导入数据
清理完重复后,直接用你最初的目标表结构(不带额外UnqId列):
-- 在SQLiteConn2中创建表 CREATE TABLE VSReports ( ReportId bigint Not Null, EvtDateTime text, ConditionCode text, Basis text, ConditionLabel text, VitalSignCode text, VitalSignLbl text, VSUnit text, VSValue text, PRIMARY KEY (ConditionCode, VitalSignCode, ReportId, EvtDateTime, Basis) );
然后导入数据(注意要指定具体表名,你之前写的FROM Priordb是语法错误):
ATTACH DATABASE 'C:/Temp/Old.db' as Priordb; INSERT INTO VSReports SELECT * FROM Priordb.VSReports;
3. 关于SQLite集群存储的关键说明
你要明确:SQLite中,主键(包括组合主键)本身就是集群索引。当你把ConditionCode, VitalSignCode, ReportId, EvtDateTime, Basis设为主键时,SQLite会自动按照这个顺序在磁盘上存储数据,完全符合你“集群存储”的需求,不需要额外的操作。
如果你暂时不想清理重复数据(不推荐)
如果因为数据量太大,清理重复耗时太长,你可以用INSERT OR IGNORE或者INSERT OR REPLACE跳过/覆盖重复行,但这会丢失数据,务必谨慎:
- 跳过重复行:
INSERT OR IGNORE INTO VSReports SELECT * FROM Priordb.VSReports; - 用新行覆盖旧行(会删除原有重复行,插入新行):
INSERT OR REPLACE INTO VSReports SELECT * FROM Priordb.VSReports;
内容的提问来源于stack exchange,提问作者BabblingREnthusiast

