管理员等人如何知道要更新什么?


How do Adminer et al know what to update?

这是我想理解的。我有以下数据库表

DROP TABLE IF EXISTS `test`;
CREATE TABLE `test` (
  `Field0` int(11) NOT NULL,
  `Field1` int(11) NOT NULL,
  `Field2` enum('a','b','c') COLLATE latin2_czech_cs NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin2 COLLATE=latin2_czech_cs;
INSERT INTO `test` (`Field0`, `Field1`, `Field2`) VALUES
(10,    11, 'a'),
(10,    13, 'b'),
(10,    13, 'a');

注意没有任何索引,唯一键... .在有人告诉我"这不是一个好主意"之前,我有一个很好的理由把这个例子串在一起。

现在假设我使用Adminer(你可以很容易地读取phpMyAdmin等)来编辑第2行

(10,13,b)

现在编辑后,如果发出的SQL是

UPDATE `test` SET Field2 = 'c' WHERE Field0 = '10' AND Field1 = '13';

MySQL将更新两行,并且表将读取

(10,11,a)
(10,13,c)
(10,13,c)

,这不是期望的结果,也不是Adminer所做的。它似乎知道要更新哪一行,并做到了这一点。我不清楚这是怎么做到的。对于许多其他语句,例如CREATE TABLE,可能故意使用无效赋值(例如:g尝试为TEXT字段分配一个长度,然后研究SQL的错误。但是,该选项不存在于行编辑,因为管理员会主动阻止您进行无效的编辑(例如,在整数列中键入字符)。

关于我能想到的唯一方法是在语句的末尾标记一个LIMIT 1 -这将工作,有点。然而,在一个包含大量字段的表中,为了帮助MySQL识别要修改的行,当一行中只有一个或两个字段发生了变化时,可能需要放入一个非常长的WHERE子句。

也许还有其他的技术可以做到这一点,而不是我不知道的那么粗糙?我将非常感激任何可能能够帮助我的人。

完成这篇文章-请不要告诉我行应该是唯一的,我应该使用索引。我很清楚这一点。这是我试图解决的最坏的情况。


我应该提到,虽然这个问题是关于MySQL的,但我实际上使用的是MariaDB 10。

您要求更新一行,但是没有可以使用的唯一标识符,因此,软件获取了与更新数据库一样多的常量数据。这个数据,Field0Field1的值不是唯一的,所以它改变了它匹配的所有行。如果(Field0, Field1)是一个唯一键,或者有一个(唯一的)主键,它可能只改变了一行。

如果(Field0, Field1)不是唯一的,并且您已经添加了LIMIT 1,它仍然可以选择更改匹配的另一个行。

如果没有一种唯一的方式来引用每一个单独的行(也就是没有null的主键),你就会有效地违反Codd的12条规则,特别是规则#2。由于"完美"的关系数据库在日常使用中大多是理论上的,不切实际的,所以数据库可以在没有严格遵从的情况下愉快地存在,但在这种情况下,如果没有唯一键,您只会让自己的生活变得困难。