避免在mySQL表中重复数据

时间:2019-05-10 22:11:53

标签: mysql database

我的DDBB中有下表:

CREATE TABLE subjects (
  subject_id int(11) NOT NULL AUTO_INCREMENT,
  subject text,
  PRIMARY KEY (subject_id, subject)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1;

这是我的桌子的一个例子:

id  | subject |
1       test        
2       ICT         
3       ICT 

键(id)不是重复的,因为它是由MySQL自动生成的,但是后两行在重复。

如何避免重复主题名称?

我已经读到可以用这样的“约束”来完成它:

ALTER TABLE subjects
ADD CONSTRAINT constraint_subject UNIQUE KEY(subject);

但是我尝试过,每次都会出错。

我知道之前已经有人问过这个问题,但是我仍然从我的PHP输入,某些主题具有相同的名称,并且程序总是允许我输入它们。

2 个答案:

答案 0 :(得分:3)

添加约束会给您一个错误,因为由于您已经有重复的数据而无法满足要求。

您必须删除重复项,然后添加约束,然后约束将起作用。

如果您现在只想选择不同的行,即使数据库中有重复的行,也可以运行以下命令:

SELECT
    *
FROM
    subjects AS s1
WHERE 
    NOT EXISTS (
        SELECT
            id
        FROM
            subjects AS s2
        WHERE
            s1.subject = s2.subject
        AND s1.id != s2.id
    );

SELECT
    s1.*
FROM
    subjects AS s1
LEFT JOIN
    subjects AS s2
    ON (s1.subject = s2.subject AND s1.id != s2.id)
WHERE 
    s2.id IS NULL

两者都会给出相同的结果,但是我发现第一个更加明确地说明了您要实现的目标。

答案 1 :(得分:2)

您不能在数据类型为TEXT的列上创建索引,因为对于索引而言,这太长了。

您可以在该列的前缀上创建索引,甚至是唯一索引。

ALTER TABLE subjects
ADD CONSTRAINT constraint_subject UNIQUE KEY(subject(191));

这意味着两个主题不能具有完全相同的前191个字符。

我认为您不应该声明包含该主题的主键。单独使用自动递增整数列作为主键更为常见。

因此您的表最终具有以下定义:

CREATE TABLE `subjects` (
  `subject_id` int(11) NOT NULL AUTO_INCREMENT,
  `subject` text,
  PRIMARY KEY (`subject_id`),
  UNIQUE KEY `constraint_subject` (`subject`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

我选择了191的长度,因为它是InnoDB索引中767字节限制(utf8mb4个字符计为4字节)的最大长度。