SQLite3中的外键不匹配

时间:2018-07-17 14:10:25

标签: sql sqlite foreign-keys primary-key

我正在将 SQLite3 用于简单的应用程序(如议程)。议程是多语言的。这就是为什么我的宴会厅使用更多语言(语言数必须是独立的)的原因

首先,我有一个表房间,其定义如下:

CREATE TABLE rooms 
(
    room_code VARCHAR2(32),
    lang_code CHAR(2),
    room_name VARCHAR(32),
    PRIMARY KEY (room_code, lang_code),
    FOREIGN KEY (lang_code) REFERENCES languages (lang_code),
    CHECK (LENGTH(lang_code) = 2),
    CHECK (room_code <> '')
);

然后我有一个表事件,定义如下:

CREATE TABLE events 
(
    room_code VARCHAR2(32) NOT NULL,
    message_code VARCHAR(64) NOT NULL,
    time_start DATETIME NOT NULL ,
    time_end DATETIME NOT NULL,
    PRIMARY KEY (message_code, room_code),
    FOREIGN KEY (room_code) REFERENCES rooms (room_code),
    -- Check the time is between 00:00 and 23:59
    CHECK (time_start and time_end BETWEEN TIME('00:00') AND TIME('23:59')),
    -- Start time must be lower than end time
    CHECK (time_start < time_end),
    -- Message code cannot be empty
    CHECK (message_code <> '') 
);

但是实际上,任何尝试插入的操作都会出现此错误:

Error: near line 91: foreign key mismatch - "events" referencing "rooms"

为什么我不能引用另一个表?我读到表B的所有外键都必须是表A中的PRIMARY KEY。但是这种依赖性对我来说还可以。表事件中的外键 room_code ,它也是表 rooms 中的主键 room_code

是否可以代替 TRIGGERS 解决此问题?实际上,如果可能的话,我想使用KEYS代替TRIGGERS。谢谢

最诚挚的问候

1 个答案:

答案 0 :(得分:1)

我相信您的问题是由于不符合:-

  

通常,外键约束的父键是主键   父表的如果它们不是主键,则父键   键列必须共同受到UNIQUE约束,或者   有一个唯一索引。如果父键列具有UNIQUE索引,   那么该索引必须使用在中指定的排序规则序列   父表的CREATE TABLE语句。例如,

SQLite Foreign Key Support

请注意主键,而不是部分主键。

简而言之,必须知道外键引用的列是唯一的。

因此,您可以为room_code列添加索引,也可以定义索引以利用UNIQUE约束,例如:-

DROP TABLE IF EXISTS events;
DROP TABLE IF EXISTS rooms;
DROP INDEX IF EXISTS room_code_idx;
CREATE TABLE IF NOT EXISTS rooms (
    room_code VARCHAR2(32) UNIQUE, --<<<<<<<<<< ADDED UNIQUE
    lang_code CHAR(2),
    room_name VARCHAR(32),
    PRIMARY KEY (room_code, lang_code),
    -- FOREIGN KEY (lang_code) REFERENCES languages (lang_code)  
    CHECK (LENGTH(lang_code) = 2),
    CHECK (room_code <> '')
);

CREATE TABLE IF NOT EXISTS events (
    room_code VARCHAR2(32) NOT NULL,
    message_code VARCHAR(64) NOT NULL,
    time_start DATETIME NOT NULL ,
    time_end DATETIME NOT NULL,
    PRIMARY KEY (message_code, room_code),
    FOREIGN KEY (room_code) REFERENCES rooms (room_code),
    -- Check the time is between 00:00 and 23:59
    CHECK (time_start and time_end BETWEEN TIME('00:00') AND TIME('23:59')),
    -- Start time must be lower than end time
    CHECK (time_start < time_end),
    -- Message code cannot be empty
    CHECK (message_code <> '') 
);

INSERT INTO rooms VALUES('room001','xx','This is room 1');
INSERT INTO events VALUES('room001','This is a message for room 1','01:00','02:00');
  • 为方便/简洁起见,注释掉lang_code的FK

结果:-

INSERT INTO rooms VALUES('room001','xx','This is room 1')
> Affected rows: 1
> Time: 0.3s


INSERT INTO events VALUES('room001','This is a message for room 1','01:00','02:00')
> Affected rows: 1
> Time: 0.301s

当然,您可以将PRIMARY KEY定义为 room_code 列,因为它必须是唯一的。

如果 room_code 列将/可能不是唯一的,并且唯一保证的唯一性将是 room_code 列和 lang_code 列的总和。您将需要定义一个复合外键(请参阅上面的链接)。