MySQL 外键验证问题

标签 mysql sql

我目前正在自学 mySQL,在将新行插入我的销售数据库时遇到了一个问题。

每次销售产品时,都会在销售数据库中添加一个新行,其中包括买家 ID(来自 users 表的外键)和买家姓名(来自 users 表的外键) .

但是我的问题如下。如果我为 id=10 的用户在销售表中插入一条新记录,并且我错误地输入了 name='Peter Smith' 而不是 name='Roger Smith',即使 'Peter Smith' 不是用户表中具有 id=10 的人的姓名,它也是成功的。

谁能指出我哪里出错了?非常感谢。

CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(30) DEFAULT NULL,
`dob` date DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `name` (`name`)
) ENGINE=InnoDB

CREATE TABLE `sales` (
`salesid` int(11) NOT NULL AUTO_INCREMENT,
`productname` varchar(30) DEFAULT NULL,
`productprice` decimal(10,0) DEFAULT NULL,
`quantity` int(11) DEFAULT NULL,
`userid` int(11) NOT NULL,
`user_name` varchar(30) DEFAULT NULL,
PRIMARY KEY (`salesid`),
KEY `FK_sales` (`userid`),
KEY `FK_name` (`user_name`),
CONSTRAINT `FK_name` FOREIGN KEY (`user_name`) REFERENCES `users` (`name`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `FK_sales` FOREIGN KEY (`userid`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB

最佳答案

您出错的地方是更新异常,因为实现违反了第三范式 (3NF)。

Each and every attribute is dependent on the key, the whole key, and nothing but the key. So help me Codd.


在您的模型中,sales 表中的user_name 依赖于sales 表的键。听起来您希望它依赖于 userid 列。

简单的解决方法是从 sales 表中删除 user_name 列。当您需要返回 user_name 时,根据 user_id 在 users 表中进行查找。例如,对 users 表的 JOIN 操作。

SELECT u.name AS user_name 
     , s.userid
     , s.productprice
     , ...
  FROM sales s
  JOIN users u
    ON u.id = s.userid

通过这种方法,我们避免了存储冗余信息。 name 属性依赖于 users 表中的 id 列。


如果强烈需要将 user_name 存储在 sales 表中,那么应用程序逻辑将需要强制执行 user_name 的规则sales 表中的一行需要与 users 表中相应行中的 name 列相同。没有强制执行这种规则的声明性约束

(外键约束仅强制执行值必须出现在引用表的某些行中的规则。)

可以添加 BEFORE INSERT 和 BEFORE UPDATE 触发器来执行规则,并进行查找并自动填充 user_name 列。

关于MySQL 外键验证问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40684855/

相关文章:

java - 将 netbeans (JAVA) 连接到 MYSQL

php - 将 mysql 行传递给评分算法?

php - Docker 无法使用 PHP 连接到 mariadb

database - 获取两个sql文件的差异

sql - SQLAlchemy允许将null作为ForeignKey

mysql - 在数据库中搜索列中具有特定值的所有表

php - 使用 PHP 将 mySQL 转换为 XLS?

sql - 从另一个表中替换 select 语句中的一行中的多个标签

mysql - sql 存储过程 Quotes()

sql - T-SQL 如何 "Flatten"前 3 行变成单行