如何在SQLite中跨表对列添加唯一约束

问题描述 投票:0回答:2

假设我有两列:一张表中的

GroupName
,另一张表中的
Username
。如何限制这些列的值,以便添加到一列的任何值在两列中都是唯一的?最好以“不混乱”的方式。

sql database sqlite
2个回答
1
投票

您提到的结构没有简单的方法。当然,有实现触发器的方法,但是比较麻烦。

替代数据模型解决了这个问题:

create table things (
    thingsId int auto_increment primary key,
    name text,
    type text,
    . . .
    check (type in ('group', 'user')),
    unique (name)
);

这会将每种类型的事物放入单个列中,然后施加唯一约束。


0
投票

您还可以使用触发器和

SELECT RAISE(FAIL, ...)
来执行此操作:

例如,假设我有一个

Shelf
表,我希望它包含
Book
Magazine
。我也不希望
Book
Magazine
在书架上有相同的标题。我真的很想对
(Shelf.ShelfID, Book.BookID OR Magazine.MagazineID)
有一个独特的约束,但该语言没有提供这一点。让我们:

创建表(注意:在现实世界的实现中,文档建议在外键上建立索引以提高性能):

CREATE TABLE Shelf (
    ShelfID INTEGER PRIMARY KEY,
    Title TEXT NOT NULL,
    UNIQUE(Title)
) STRICT;

CREATE TABLE Book (
    BookID INTEGER PRIMARY KEY,
    ShelfID INTEGER NOT NULL,
    Title TEXT NOT NULL,
    FOREIGN KEY (ShelfID) REFERENCES Shelf(ShelfID) ON DELETE CASCADE,
    UNIQUE(Title)
) STRICT;

CREATE TABLE Magazine (
    MagazineID INTEGER PRIMARY KEY,
    ShelfID INTEGER NOT NULL,
    Title TEXT NOT NULL,
    FOREIGN KEY (ShelfID) REFERENCES Shelf(ShelfID) ON DELETE CASCADE,
    UNIQUE(Title)
) STRICT;

创建视图和触发器(这是神奇的部分):

CREATE VIEW vw_Book_Magazine_Shelf_AllTitles AS
SELECT s.ShelfID, b.Title
FROM Shelf s JOIN Book b ON s.ShelfID = b.ShelfID
UNION ALL
SELECT s.ShelfID, m.Title
FROM Shelf s JOIN Magazine m ON s.ShelfID = m.ShelfID
;

CREATE TRIGGER tr_Book_Insert_CheckUniqueTitle
BEFORE INSERT ON Book
FOR EACH ROW
BEGIN
    SELECT RAISE(FAIL, 'title already exists in Shelf')
    FROM vw_Book_Magazine_Shelf_AllTitles
    WHERE ShelfID = NEW.ShelfID AND Title = NEW.Title;
END;


CREATE TRIGGER tr_Book_Update_CheckUniqueTitle
BEFORE UPDATE ON Book
FOR EACH ROW
BEGIN
    SELECT RAISE(FAIL, 'title already exists in Shelf')
    FROM vw_Book_Magazine_Shelf_AllTitles
    WHERE ShelfID = NEW.ShelfID AND Title = NEW.Title;
END;

CREATE TRIGGER tr_Magazine_Insert_CheckUniqueTitle
BEFORE INSERT ON Magazine
FOR EACH ROW
BEGIN
    SELECT RAISE(FAIL, 'title already exists in Shelf')
    FROM vw_Book_Magazine_Shelf_AllTitles
    WHERE ShelfID = NEW.ShelfID AND Title = NEW.Title;
END;


CREATE TRIGGER tr_Magazine_Update_CheckUniqueTitle
BEFORE UPDATE ON Magazine
FOR EACH ROW
BEGIN
    SELECT RAISE(FAIL, 'title already exists in Shelf')
    FROM vw_Book_Magazine_Shelf_AllTitles
    WHERE ShelfID = NEW.ShelfID AND Title = NEW.Title;
END;

最后,让我们测试一下:

INSERT INTO Shelf(ShelfID, Title) Values(1, 'Shelf Title');
INSERT INTO Book(BookID, ShelfID, Title) VALUES (1, 1, 'Book Title');
INSERT INTO Magazine(MagazineID, ShelfID, Title) VALUES (1, 1, 'Mag Title');
-- this fails
UPDATE Magazine SET Title = 'Book Title' WHERE Title = 'Mag Title';
© www.soinside.com 2019 - 2024. All rights reserved.