代码之家  ›  专栏  ›  技术社区  ›  nickf

在两个表之间强制使用唯一值

  •  13
  • nickf  · 技术社区  · 16 年前

    在MySQL中,是否可以强制两个表之间的唯一性?

    我有两个表,都描述用户。这些表中的用户以前用于两个不同的系统,但是现在我们正在合并身份验证系统,我需要确保这两个表中有唯一的用户名。(现在把它们放在一张桌子上太麻烦了)。

    7 回复  |  直到 16 年前
        1
  •  17
  •   Bill Karwin    16 年前

    不能跨多个表声明唯一约束,而且MySQL根本不支持检查约束。但是您可以设计一个触发器来搜索另一个表中的匹配值。下面是一个测试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
    

    对于每个表,更新时也需要类似的触发器,但删除时不需要任何触发器。

        2
  •  4
  •   Mnyikka    13 年前

    最好的方法是用唯一的列声明另一个表,并让多个表引用这些表

        3
  •  3
  •   professorsloth Rohit Goel    11 年前

    也许不是直接回答你的问题,但是:

    您应该考虑重写代码并重新构造数据库,以便将这两个表合并为一个表。

    您现在尝试实施的设计将使您的代码和数据库模式复杂化,并且将使任何进一步升级到其他数据库软件或框架变得更加困难。

        4
  •  1
  •   kmkaplan    16 年前

    您可以添加一个以一列作为主键的额外表。然后在每个旧用户表上创建一个触发器,将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;
    
        5
  •  0
  •   cliff.meyers    16 年前

    显然,如果两个表中已经有重复项,则必须手动解决该问题。向前移动,您可以编写一个触发器,检查两个表是否已经存在该值,然后将其应用到两个表。

        6
  •  0
  •   Vilx-    16 年前

    更改ID列的类型是否可以负担得起?然后,您可以选择在任意多个表上都是唯一的guid。

        7
  •  -1
  •   tuinstoel    16 年前

    我不知道MySQL,但这是在Oracle中实现它的方法,我相信MySQL也支持物化视图。

    在这两个表上创建物化视图。并在此视图上添加唯一约束。

    每次提交对两个基表之一的更改时,都需要刷新此视图。