如何在不删除现有重复记录的情况下为2列添加唯一约束?

时间:2013-07-17 22:03:24

标签: mysql

我有这个表,col1 col2 col3,col1是主键,现在我想为col2和col3添加唯一约束,我使用了alter table add constraint,但似乎表中已经有重复的记录,所以我必须删除它们以使其工作,但是,如果我需要保留所有现有记录,我如何确保新添加的记录是col2和col3中的唯一约束?

2 个答案:

答案 0 :(得分:1)

如果我理解正确,您希望保留当前的重复项,但是您要确保不添加任何新的副本,对吧?我个人会按照上面的评论,但我知道如果这不符合您的业务需求。

不幸的是,当您描述约束时,约束不符合您的需求。您可能希望控制插入数据的软件中的重复逻辑,而不是表级。 例如,如果表中不存在val3,则以下内容仅添加行。合理?

INSERT INTO MyTable (col1, col2, col3, col4)
VALUES (val1, val2, val3, val4) WHERE NOT col3 = val3;

或者您可以触发INSTEAD OF触发器。 SQL有一个特殊的临时'插入'表,您可以在值进入之前对其进行比较。所以你说,“插入这些值,但等等!只有在temp'insert'表中的行与MyTable中的现有行不匹配时才插入它们。“

CREATE TRIGGER no_duplicates_in_MyTable ON MyTable
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON
IF (NOT EXISTS (SELECT M.val3
      FROM MyTable M, inserted I
      WHERE M.val3 = I.val3))
   INSERT INTO MyTable
      SELECT val1, val2, val3, val4
      FROM inserted
END

或者你可以使用AFTER INSERT触发器处理表级别的逻辑,但它有点不稳定。在某些情况下,您可以删除现有的重复项。像这样的东西;

CREATE TRIGGER delete_duplicates_MyTable
AFTER INSERT ON MyTable
BEGIN
   DELETE FROM MyTable 
   WHERE val3 NOT IN (SELECT MIN(val3) 
                             FROM MyTable 
                             WHERE val1 = new. val1)
   AND val1 = new. val1;
END;

如果您有任何疑问或者这不符合您的业务需求,请与我们联系。

编辑:@Rik是正确的,这些是INSERT触发器,因此它们不适用于更新,允许任何人的代码将值更改为重复。尝试UPDATE触发器。您可以将这些不断变化的INSERT改为更新。

答案 1 :(得分:0)

就个人而言,我会赞同对方的评论。你应该真正修复数据,然后添加约束。

然而,仅仅为了它,一个可能的解决方案可能是使用MERGE引擎。基本上,您将现有数据保存在一个表中,并创建几乎相同的第二个表。唯一不同的是,这次索引是独一无二的。

见这个例子:

CREATE TABLE t1 (
   a INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
   message CHAR(20),
   key whatever (message)
   ) ENGINE=MyISAM;

CREATE TABLE t2 (
   a INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
   message CHAR(20),
   unique key whatever (message)
   ) ENGINE=MyISAM;

INSERT INTO t1 (message) VALUES ('Testing'),('Testing'),('t1');
INSERT INTO t2 (message) VALUES ('Testing'),('table'),('t2');

CREATE TABLE total (
   a INT NOT NULL AUTO_INCREMENT,
   message CHAR(20), INDEX(a))
   ENGINE=MERGE UNION=(t1,t2) INSERT_METHOD=LAST;

select * from total; 
/*Here you can see, that there are duplicate values*/

insert into total (message) values ('Testing');
/*but this results in a duplicate key error*/

insert into total (message) values ('it work\'s');
/*whereas this doesn't*/

详细了解MERGE引擎here