【问题标题】:MySQL: UPDATEing a row with no guaranteed unique fieldMySQL:更新没有保证唯一字段的行
【发布时间】:2010-06-25 21:08:18
【问题描述】:

我正在使用一个旧的 MySQL 表,它用作各种日志。好像

CREATE TABLE `queries` (
  `Email` char(32) NOT NULL DEFAULT '',
  `Query` blob,
  `NumRecords` int(5) unsigned DEFAULT NULL,
  `Date` date DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

现在,我需要能够UPDATE 这个表中的记录(不要问为什么,我不知道)。通常,我会这样做

UPDATE table SET ... WHERE unique_column = value

但在这种情况下,我没有可以使用的唯一列。

是否有解决此问题的方法,还是我只需要努力输入一个不错的标准INT NOT NULL AUTO_INCREMENT

【问题讨论】:

  • 你怎么知道要更新哪些行?
  • @Doug,嗯,这确实是问题的核心。
  • 如果您不知道哪些行,为什么要更新行?你想做什么?
  • 听起来你是在听从不喜欢好的设计的人的命令。
  • 你面前有两个丧尸。我大喊,射中脑中的丧尸!两个都拍没关系。

标签: php sql mysql database-design


【解决方案1】:
UPDATE queries 
SET ... 
WHERE Email = value1 
  AND Query = value2 
  AND NumRecords = value3 
  AND Date = value4 
LIMIT 1;

【讨论】:

  • 那将任意使用返回的第一行,也就是说——你不能保证它总是一致地更新同一行。添加 ORDER BY 也无济于事。
  • @OMG 小马,所以?如果所有字段都匹配,则行无法区分。
  • @Doug Currie - 那么为什么不任意更改所有匹配的记录而不是任意更改一个呢?如果有两行在所有列上都相同,则根据定义,它们是同一个实例。
  • @Doug 正如我在 cmets 中对我的回答所说的那样,您是对的,这里没有立即需要唯一 ID,但我仍然认为不使用唯一 ID 是一种不好的做法,因为潜在的并发问题.例如,在具有两个并发用户/连接的情况下,不可能针对锁定特定记录;此外,并发更新可能会出错。不过,对于 OP 的情况,这可能没问题。 +1
  • @Doug Currie:鉴于数据相同,您不理解 OP 要求他们引用特定 的原因是什么?
【解决方案2】:

唯一的标识符是唯一可靠的方法。只需添加一个auto_increment 列并完成它。

有关详细信息,包括一些解决方法(尽管它们都不是完美的!),请查看this question,其中 OP 有一个没有唯一标识符且无法更改的表。

更新:正如 Doug Currie 指出的那样,这并不完全正确:这里不需要唯一的 ID。我仍然强烈推荐始终使用一个的做法。如果两个用户决定同时更新彼此完全相同的两个不同行(例如,通过在 GUI 中选择一行),则可能会发生冲突,因为无法定义哪个行是哪个操作的目标。这是一种微观的可能性,在手头的情况下可能完全可以忽略不计,但这不是好的设计。

【讨论】:

  • +1:如果Date 列是 DATETIME 数据类型,那么它将是候选数据类型,因为 DATETIME 精确到微秒。但是如果列上没有唯一键,则无法确保这种情况......
  • @Doug 如果他只想定位具有完全相同内容的两行之一怎么办?为什么只有一个?
  • @Pekka,SQL 是面向集合的;不能有两行内容相同。如果这是 SQL 的扩展,那么方言应该支持 UPDATE ... WHERE ... LIMIT 1;并且更新哪个匹配行都没有关系,因为它们是相同的。
  • 正是我要说的,Pekka。使用单个电子邮件地址 (Email) 的人完全有可能在同一天 (Date) 执行完全相同的查询 (Query),返回相同数量的结果 (NumRecords)。如果发生这种情况,我希望能够区分两者。
  • @Austin Hyde - 然后根据您的设计,这两行代表完全相同的事件。一旦您回答了人类如何区分这两组信息的问题,您就会知道需要如何更改数据库以区分它们。
【解决方案3】:

这里有两个不同的问题。首先,是对表进行重复数据删除。这是一个完全不同的问题和解决方案,可能涉及添加 auto_increment 列。但是,如果您不打算对表进行重复数据删除,那么根据定义,具有相同数据的两行代表相同的信息实例,如果它们符合过滤条件,则两者都应该进行更新。因此,要么添加唯一键,对表进行去重(在这种情况下,唯一性基于所有列的组合),要么更新所有匹配的行。

【讨论】:

    【解决方案4】:

    如果您不知道这一点,它会影响性能,但您不需要在更新记录时在 WHERE 子句中使用主键。您可以通过指定现有值来选择一行:

    UPDATE queries
    SET Query = 'whatever'
    WHERE Email = 'whatever@whatever.com' AND
      Query = 'whatever' AND
      NumRecords = 42 AND
      Date = '1969-01-01'
    

    如果有重复的行,为什么不全部更新,反正你无法区分?

    您无法使用 MySQL 查询浏览器中的 GUI 界面来做到这一点。

    如果您需要开始区分行,然后添加一个自动增量整数字段,您也可以在 MySQL 查询浏览器中编辑它们。

    【讨论】:

      【解决方案5】:

      先删除重复项。在表(或与此相关的任何表)中有重复行有什么意义?

      删除重复项后,您可以实施密钥,您的问题就解决了。

      【讨论】:

      • 因为,在这种情况下,重复的行可能并不是真正的重复,因为N个重复的行意味着同一封邮件的人执行的同一查询在同一天返回了相同的结果,执行了N次。
      猜你喜欢
      • 1970-01-01
      • 2018-08-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-16
      • 2019-11-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多