添加mysql约束或触发器

添加mysql约束或触发器,mysql,triggers,constraints,Mysql,Triggers,Constraints,我有一个关于MySQL中的触发器和唯一约束的快速问题。我来举个简单的例子 我有两个表,“帐户”和“用户”。这两个表之间的关系是1(帐户)对多(用户)。因此,如果您调出一个具有唯一id的帐户表,您将遇到该帐户的多个用户。用户表中有一列称为“用户类型”“用户类型”可以是“管理员”、“来宾”、“试用版”。“帐户”必须有一个将“admin”作为“user\u type”的用户。每个帐户只能有一个“管理员” 那么,有没有一种方法可以添加一个唯一的约束,使任何帐户只能有一个“admin”用户类型?或者它必须

我有一个关于MySQL中的触发器和唯一约束的快速问题。我来举个简单的例子

我有两个表,“帐户”和“用户”。这两个表之间的关系是1(帐户)对多(用户)。因此,如果您调出一个具有唯一id的帐户表,您将遇到该帐户的多个用户。用户表中有一列称为“用户类型”“用户类型”可以是“管理员”、“来宾”、“试用版”。“帐户”必须有一个将“admin”作为“user\u type”的用户。每个帐户只能有一个“管理员”

那么,有没有一种方法可以添加一个唯一的约束,使任何帐户只能有一个“admin”用户类型?或者它必须是一个触发器,因为它是MySQL


谢谢

如果您实现了组,而不是将其作为用户表的属性,那么系统将更加灵活

话虽如此,显然您可以使用触发器强制执行您的业务规则

但是,有一种方法可以使用约束,至少在部分意义上是这样

创建一个表:

AccountAdmin
------------
account_admin_id (pk)
account_id (fk) Add unique constraint
user_id (fk)
一旦您拥有帐户_id的唯一索引,您就可以强制执行每个帐户只能有一个管理员的规则

创建管理员用户时,需要在AccountAdmin中插入一行。如果管理员已经存在,该约束将阻止您这样做

话虽如此,为了从一个管理员更改为另一个管理员,您需要首先从该表中删除该行,然后添加新的一行

当您开始考虑支持“变更管理”或“升级到管理”之类的功能时,在我看来,触发器甚至更不理想。p> 关于触发器:

在需要系统可扩展到“n”个用户的系统上做了大量工作之后,我学到了要避免的一件事是在数据持久性级别创建瓶颈。MySQL触发器和存储过程本质上是不可伸缩的

您正在数据库中集中一个瓶颈并限制并发性。在触发器中执行此练习时,如果不锁定表,则无法确保在查询以确保组织没有管理员时,另一个查询不会在插入管理员之前插入。这也是一种反模式,必须抛出一个数据库异常并处理它,因为它根本不是一个错误(即,已经存在一个管理员)


如果有一种方法可以让您将此代码移动到应用程序中(在本例中是这样的),那么这就是一种更具可伸缩性的解决方案

确保每个帐户只有一个管理员用户的最简单方法是将一个外键指向用户行(即管理员)

CREATE TABLE Users (
  user_id INT AUTO_INCREMENT PRIMARY KEY,
  account_id INT
);

CREATE TABLE Account (
  account_id INT AUTO_INCREMENT PRIMARY KEY,
  admin_user_id INT NOT NULL
);

ALTER TABLE Account ADD FOREIGN KEY (admin_user_id) 
  REFERENCES Users (user_id);

ALTER TABLE Users ADD FOREIGN KEY (account_id) 
  REFERENCES Account(account_id);

INSERT INTO Users () VALUES ();
SET @uid = LAST_INSERT_ID();
INSERT INTO Account (admin_user_id) VALUES (@uid);
UPDATE Users SET account_id = LAST_INSERT_ID() WHERE user_id = @uid;
确保每个帐户的用户仅限于一个管理员,我假设其他类型的多个用户有点棘手。但是通过MySQL 5.7中的虚拟列,我们可以做到这一点

ALTER TABLE Users 
  ADD COLUMN user_type ENUM('admin', 'guest', 'trial') NOT NULL DEFAULT 'guest',
  ADD COLUMN is_admin TINYINT(1) AS (IF(user_type='admin',1,NULL)) STORED,
  ADD UNIQUE KEY (account_id, is_admin);

SELECT * FROM Users;
+---------+------------+-----------+----------+
| user_id | account_id | user_type | is_admin |
+---------+------------+-----------+----------+
|       1 |          1 | guest     |     NULL |
+---------+------------+-----------+----------+

INSERT INTO Users (account_id, user_type) VALUES (1, 'admin');

SELECT * FROM Users;
+---------+------------+-----------+----------+
| user_id | account_id | user_type | is_admin |
+---------+------------+-----------+----------+
|       1 |          1 | guest     |     NULL |
|       2 |          1 | admin     |        1 |
+---------+------------+-----------+----------+

INSERT INTO Users (account_id, user_type) VALUES (1, 'admin');
ERROR 1062 (23000): Duplicate entry '1-1' for key 'account_id'

虚拟列上的唯一键忽略空值。因此,任何数量的来宾或试用用户都可以存在,并且它们在虚拟列中都用NULL表示。但是每个帐户可以有一个管理员用户,其值在虚拟列中为1。

假设我们已经过了添加新表的阶段。如果没有这个表,触发器是我唯一可用的路径吗?你怎么可能通过添加一个表来关联两个现有表的键呢?这只是一个例子。在我的回答中添加了更多内容来解决你的问题。