【问题标题】:Enforce unique values across two tables在两个表中强制执行唯一值
【发布时间】:2009-01-03 07:26:07
【问题描述】:

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

我有两个表,都描述了用户。这些表中的用户以前用于两个不同的系统,但是现在我们正在合并我们的身份验证系统,我需要确保这两个表中有唯一的用户名。 (现在将它们全部放在一张表中工作量太大)。

【问题讨论】:

    标签: mysql indexing


    【解决方案1】:

    您可以添加一个带有单列的额外表作为主键。然后在每个旧用户表上创建一个触发器,以将 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;
    

    【讨论】:

      【解决方案2】:

      你不能跨多个表声明一个 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 触发器。

      【讨论】:

        【解决方案3】:

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

        您应该考虑重写代码并重组数据库以将这两个表合并为一个。

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

        【讨论】:

          【解决方案4】:

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

          【讨论】:

          • 我不认为这实际上有帮助,因为没有什么能阻止来自不同表的 2 条记录引用第三个表上相同的唯一列。也许你可以通过某种多态关联来做到这一点。
          【解决方案5】:

          显然,如果两个表中已经存在重复项,您将不得不手动解决该问题。接下来,您可以编写一个触发器来检查两个表以查看值是否已经存在,然后将其应用于两个表。

          【讨论】:

            【解决方案6】:

            是否可以负担得起更改 ID 列的类型?然后,您可以选择在任意数量的表中唯一的 GUID。

            【讨论】:

              【解决方案7】:

              我不了解 MySQL,但这就是您在 Oracle 中可以做到的方式,我相信 MySQL 也支持物化视图。

              您在这两个表上创建了一个物化视图。然后在这个视图上添加一个唯一的约束。

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

              【讨论】:

              • 对不起,MySQL 不支持物化视图。
              • MySQL 也没有正确执行外键完整性。 :(
              • 即使使用 InnoDB 也不行?我以为第 5 版做到了。
              • MySQL 的默认 MyISAM 存储引擎不强制执行外键,但 InnoDB 易于使用。 InnoDB 已经支持外键超过 4 年了。
              猜你喜欢
              • 2017-03-25
              • 2011-01-18
              • 2010-09-10
              • 2021-01-06
              • 1970-01-01
              • 1970-01-01
              • 2011-08-26
              • 1970-01-01
              • 2011-06-19
              相关资源
              最近更新 更多