【问题标题】:MySQL Downgrading Composite Primary Key to be more restrictiveMySQL 将复合主键降级为更具限制性
【发布时间】:2016-07-19 17:33:07
【问题描述】:

我有下表用于跟踪正在观看支持票的用户

CREATE TABLE IF NOT EXISTS crm_ticketwatcher (
  ticketid int(10) unsigned NOT NULL DEFAULT '0',
  employeeid int(10) unsigned NOT NULL DEFAULT '0',
  contactid int(10) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (ticketid,employeeid,contactid)
) ENGINE=MyISAM;

我想要一个从主键中删除 contactid 的降级脚本。

表格内容有点像这样

ticketid|employeeid|contactid
--------|----------|---------
5       |5         |0
5       |8         |0
5       |0         |2
5       |0         |3

当我运行我的(不成功的)降级脚本时,

ALTER TABLE crm_ticketwatcher DROP PRIMARY KEY, ADD PRIMARY KEY (ticketid, employeeid);

我收到以下错误:

ERROR 1062 (23000) at line 1: Duplicate entry '306-0' for key 'PRIMARY'

因为现在有 2 行设置了主键 (5, 0)

从表中删除其他行并保存最后出现的行的最佳方法是什么?

我们使用的是 MySQL 5.7.13,因此 IGNORE 关键字不是一个选项。

谢谢。

【问题讨论】:

  • 您能否告诉我您将获得“最后出现”信息的表的结构?喜欢日期。或者您只想保留最高或最低的联系方式行?你保留的是 (5, 0, 2) 还是 (5, 0, 3)?
  • (5, 0, 3) 将被保留,因为它是最低行
  • 我认为 Eggyal 的回答应该适用于这种情况。
  • 它适用于这种情况,因为 3 恰好大于 2,但在完整表中,最低行的 contactid 没有显示这一点。

标签: mysql database primary-key database-migration composite-primary-key


【解决方案1】:

ALTER TABLE Syntax 中所述:

IGNORE 是标准 SQL 的 MySQL 扩展。它控制ALTER TABLE 在新表中的唯一键上存在重复项或启用严格模式时出现警告时的工作方式。如果未指定IGNORE,则如果发生重复键错误,则复制将中止并回滚。如果指定了IGNORE,则仅使用在唯一键上有重复的行中的一行。其他冲突的行被删除。不正确的值将被截断为最接近的匹配可接受值。

因此,您可以这样做:

ALTER IGNORE TABLE crm_ticketwatcher
  DROP PRIMARY KEY,
  ADD PRIMARY KEY (ticketid, employeeid);

但请注意,保留哪些“重复”行将是不确定的。

如果您想要更确定的结果,或者使用 MySQL v5.7.4 及更高版本(已从中删除 IGNORE),您可以先使用多表 DELETE 语法执行自联接:

DELETE c1
FROM   crm_ticketwatcher c1
  JOIN crm_ticketwatcher c2 USING (ticketid, employeeid)
WHERE  c1.contactid < c2.contactid -- or whatever logic you prefer

【讨论】:

  • 我在使用它时遇到了一个错误,并在 MySQL 文档页面 As of MySQL 5.7.4, the IGNORE clause for ALTER TABLE is removed and its use produces an error. 上找到了这个
  • @GavinGassmann:为避免疑问,您使用的是 MySQL ≥5.7.4 的版本?
  • 是的,我也会将版本添加到 OP 中。
  • 您能说明一下 JOIN USING 语句的工作原理吗?我很难在这里可视化复合键。我将用什么替换 where 语句以保留最后出现/最低的行?
  • @GavinGassmann: t1 JOIN t2 USING (a, b)t1 JOIN t2 ON t1.a = t2.a AND t1.b = t2.b 的简写(附加效果是在结果集中每个这样的列只有一个,这样它们就可以在没有表限定的情况下被明确引用)。您认为什么是“最后出现/最低行”(请记住,在 SQL 中,表没有任何先天排序)?如上所述,我的DELETE 语句将为每个(ticketid, employeeid) 保留最大contactid 的记录,但删除所有其他记录。
猜你喜欢
  • 2013-06-02
  • 1970-01-01
  • 1970-01-01
  • 2023-04-06
  • 2012-08-23
  • 1970-01-01
  • 2013-03-05
  • 1970-01-01
  • 2015-11-28
相关资源
最近更新 更多