我目前正在自学 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/