【发布时间】:2009-01-03 07:26:07
【问题描述】:
是否可以在 MySQL 中的两个表之间强制执行唯一性?
我有两个表,都描述了用户。这些表中的用户以前用于两个不同的系统,但是现在我们正在合并我们的身份验证系统,我需要确保这两个表中有唯一的用户名。 (现在将它们全部放在一张表中工作量太大)。
【问题讨论】:
是否可以在 MySQL 中的两个表之间强制执行唯一性?
我有两个表,都描述了用户。这些表中的用户以前用于两个不同的系统,但是现在我们正在合并我们的身份验证系统,我需要确保这两个表中有唯一的用户名。 (现在将它们全部放在一张表中工作量太大)。
【问题讨论】:
您可以添加一个带有单列的额外表作为主键。然后在每个旧用户表上创建一个触发器,以将 id 插入到这个额外的表中。
create table users1 (
user_id integer primary key,
username varchar(8) not null unique
);
create table users2 (
user_id integer primary key,
username varchar(8) not null unique
);
create table all_usernames (
username varchar(8) primary key
);
create trigger users1_insert before insert on users1 for each row
insert into all_usernames values(new.username);
create trigger users2_insert before insert on users2 for each row
insert into all_usernames values(new.username);
create trigger users1_update before update on users1 for each row
update all_usernames set username = new.username
where username = old.username;
create trigger users2_update before update on users2 for each row
update all_usernames set username = new.username
where username = old.username;
create trigger users1_delete before delete on users1 for each row
delete from all_usernames where username = old.username;
create trigger users2_delete before delete on users2 for each row
delete from all_usernames where username = old.username;
然后你可以用
填充表格insert into all_usernames select username from users1;
insert into all_usernames select username from users2;
【讨论】:
你不能跨多个表声明一个 UNIQUE 约束,而且 MySQL 根本不支持 CHECK 约束。但是您可以设计一个触发器来搜索另一个表中的匹配值。这是一个测试 SQL 脚本:
DROP TABLE IF EXISTS foo;
CREATE TABLE FOO (username VARCHAR(10) NOT NULL);
DROP TABLE IF EXISTS bar;
CREATE TABLE BAR (username VARCHAR(10) NOT NULL);
DROP TRIGGER IF EXISTS unique_foo;
DROP TRIGGER IF EXISTS unique_bar;
DELIMITER //
CREATE TRIGGER unique_foo BEFORE INSERT ON foo
FOR EACH ROW BEGIN
DECLARE c INT;
SELECT COUNT(*) INTO c FROM bar WHERE username = NEW.username;
IF (c > 0) THEN
-- abort insert, because foo.username should be NOT NULL
SET NEW.username = NULL;
END IF;
END//
CREATE TRIGGER unique_bar BEFORE INSERT ON bar
FOR EACH ROW BEGIN
DECLARE c INT;
SELECT COUNT(*) INTO c FROM foo WHERE username = NEW.username;
IF (c > 0) THEN
-- abort insert, because bar.username should be NOT NULL
SET NEW.username = NULL;
END IF;
END//
DELIMITER ;
INSERT INTO foo VALUES ('bill'); -- OK
INSERT INTO bar VALUES ('bill'); -- Column 'username' cannot be null
对于每个表,您还需要类似的 ON UPDATE 触发器,但您不需要任何 ON DELETE 触发器。
【讨论】:
也许不能直接回答你的问题,但是:
您应该考虑重写代码并重组数据库以将这两个表合并为一个。
您现在尝试实施的设计将使您的代码和数据库架构复杂化,并且会使进一步升级到其他数据库软件或框架变得更加困难。
【讨论】:
最好的方法是声明另一个具有唯一列的表,并让多个表引用这些表
【讨论】:
显然,如果两个表中已经存在重复项,您将不得不手动解决该问题。接下来,您可以编写一个触发器来检查两个表以查看值是否已经存在,然后将其应用于两个表。
【讨论】:
是否可以负担得起更改 ID 列的类型?然后,您可以选择在任意数量的表中唯一的 GUID。
【讨论】:
我不了解 MySQL,但这就是您在 Oracle 中可以做到的方式,我相信 MySQL 也支持物化视图。
您在这两个表上创建了一个物化视图。然后在这个视图上添加一个唯一的约束。
每次提交对两个基表之一的更改时,都需要刷新此视图。
【讨论】: