您本质上想要做的是使用户和位置的组合在您的桌子上独一无二。
有几个选项可以实现这一点,我将按照您应该考虑的顺序描述这些选项,因为前者比后者更自然。
选项 1:在您的表中具有唯一约束
你可以把你想要的约束直接放在你的表中:
CREATE TABLE Permission (
permissionID INTEGER PRIMARY KEY UNIQUE,
user INTEGER,
location INTEGER
unique (user, location)
);
这是表达您的要求的最自然的选择。需要注意的是,在现有表上添加和删除此选项并不容易。有关如何将此选项添加到现有表的信息,请参阅本文的附件 2。
如果您现在尝试在表中插入重复条目,您会得到以下结果:
sqlite> insert into Permission (user, location) values (1, 2);
Error: UNIQUE constraint failed: Permission.user, Permission.location
选项 2:创建唯一索引
也可以创建auniqe索引
CREATE TABLE Permission (
permissionID INTEGER PRIMARY KEY UNIQUE,
user INTEGER,
location INTEGER
);
CREATE UNIQUE INDEX user_location ON Permission (user,location);
如果您尝试使用此选项插入重复条目,则会收到与第一个选项完全相同的错误消息:
sqlite> insert into Permission (user, location) values (1, 2);
Error: UNIQUE constraint failed: Permission.user, Permission.location
您可能会询问此选项与第一个选项 and so have many others 之间的区别。正如sqlite documentation 解释的那样,在内部它可能以完全相同的方式实现。归根结底,从表中添加和删除索引比在表上添加和删除唯一约束要容易得多。
选项 3:使用触发器
为了完整起见,也可以使用触发器来防止插入重复项,尽管我很难想象为什么您应该更喜欢这个选项。这是对INSERT 做出反应的最通用方式,您的示例可能如下所示:
CREATE TRIGGER avoid_duplicate_user_locations
BEFORE INSERT
ON Permission
when exists (select * from Permission where user = new.user and location = new.location)
BEGIN
SELECT
RAISE (ABORT,'duplicate entry');
END;
如果您尝试使用此选项插入重复条目,您将遇到您在触发器中指定的错误消息:
sqlite> insert into Permission (user, location) values (1, 2);
Error: duplicate entry
附件 1:删除现有重复项
如果您的表中已有重复项,以下代码将帮助您删除它们。如果你想应用第一个或第二个选项,你必须这样做。
DELETE FROM Permission
WHERE permissionID NOT IN
(SELECT MIN(permissionID) FROM Permission GROUP BY user,location );
附件 2:向表中添加唯一约束
如果您已经为没有UNIQUE 约束的表创建了架构,这里有一个如何添加它的秘诀。
CREATE TABLE Permission2 (
permissionID INTEGER PRIMARY KEY UNIQUE,
user INTEGER,
location INTEGER,
unique (user, location)
);
INSERT INTO Permission2
SELECT *
FROM Permission;
DROP Table Permission;
ALTER TABLE Permission2
RENAME TO Permission;