【问题标题】:How to select a multiple column primary key of an inserted row?如何选择插入行的多列主键?
【发布时间】:2015-01-16 19:07:37
【问题描述】:

问题:

我在 MySQL 中有下表。 对于这个例子,假设世界上只有一个人(并且永远会有)叫“Tom”“Bell”。所以 (name, surname) 是我表中的主键。每个人都有他的薪水,一个无符号整数。

CREATE TABLE IF NOT EXISTS `user` (
  `name` varchar(64) NOT NULL DEFAULT 'Default_name',
  `surname` varchar(64) NOT NULL DEFAULT 'Default_surname',
  `salary` int(10) unsigned NOT NULL DEFAULT '0',
  UNIQUE KEY `id` (`name`,`surname`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

每当我使用 PHP 脚本插入一行时,我希望我的函数返回插入行的主键(数组键 => 值)。

从 PHP 上下文中,我不知道表 'user' 的主键由什么组成,并且我并不总是需要设置所有主键值(示例 2,非常愚蠢,但可能)。

可以向我的插入函数添加另一个参数(例如,我可以传递表名,在本例中为“用户”)。

如果这很重要,我正在使用 PDO(php 数据对象)连接我的 MySQL 数据库。

示例 1:

$db->insert('INSERT INTO `user` (`name`,`surname`,`salary`) VALUES ('Tom','Bell','40');');

应该返回一个数组:

$arr = ['name' => 'Tom', 'surname' => 'Bell'];

示例 2:

$db->insert('INSERT INTO `user` (`name`,`salary`) VALUES ('Nelly','40');');

应该返回一个数组:

$arr = ['name' => 'Nelly', 'surname' => 'Default_surname'];

免责声明和其他信息:

  1. 我知道这不是一个精心设计的表,我可以使用 auto_increment id 列来使它更容易,也可能更有效。这只是一个展示问题的示例,无需解释我的项目结构。

  2. 不失一般性:使用诸如“getLastInsertId()”或“@@identity”之类的函数将返回0,我猜原因是因为表没有auto_increment 列。

    李>
  3. 我尝试了什么?什么都没有(除了第 2 点中所述的事情(我确信它不会起作用)并正在寻找解决方案)。

【问题讨论】:

  • 是否有任何实际或正当的理由为什么你会竭尽全力让你的代码和生活变得悲惨以扼杀性能和可用性?我只是想知道为什么有人会这样做,因为您知道随之而来的许多陷阱。
  • “无需解释我的项目结构”可能暗示我已经有了一些天才计划。好吧.. 我只是在编写一个使用 PDO 的数据库/查询类。然而 PDO 有一些烦人的事情,比如无法使用安全字符串来绑定“IN(:array)”语句(它确实保护了它,但它不会像某些人期望的那样工作)。我正在尝试自己解决类似的问题(当然整体效率会降低)。以数组形式返回主键的插入查询将是一件很棒的事情,但如果没有它,一切都可以解决。

标签: php mysql sql


【解决方案1】:

解决这个问题没有“好的”方法。使用 auto_increment 的原因之一是为了避免出现您所描述的问题。

现在,为了避免我的答案是只考虑一半情况的答案之一 - 我确实意识到有时您会继承一个项目,或者您只是在初始阶段搞砸了,您必须迅速解决问题。

反思您的示例-您的 PK 是自然 PK,而不是像 auto_increment 那样的代理。由于这个事实,这意味着你总是知道 PK。

在您的示例 #1 中 - 您插入了 Tom Bell - 这意味着您知道 PK 是 Tom Bell,因为您指示 MySQL 插入它。因此,既然您在插入之前就知道 PK 是什么,那么您就知道如何返回它了。

在您的示例 #2 中,您仅指定了 PK 的一部分。但是,您的表定义表明姓名和姓氏的默认值为Default_surname。这意味着,如果您省略 PK 的任何一部分,您就会知道它将采用默认值。这也意味着您在插入之前就已经知道 PK 是什么。

由于您必须使用自然 PK 而不是代理,因此“了解”它的责任将转移给您而不是 RDBMS。 没有其他方法可以执行此操作。如果您允许默认值变为null,问题会变得更加复杂。这将允许您插入超过 1 个 Tomnull 作为姓氏,并且索引约束将不适用(null 不等于 null,因此 (tom, null) 不等于 (tom, null) 和insert 可以继续)。

长话短说,您需要一个代理 PK 或 auto_increment。它会根据描述完成您需要的一切。如果你不能使用它,那么你手上就有一个可能无法解决的大问题。

【讨论】:

  • 我要指出的一点:如果一个列属于主键,它不能保持'null'。即使在创建数据库时跳过 NOT NULL 约束,主键也会自动将“NOT NULL”设置为所有列。
  • 你是正确的PK,我的错误忽略它。但是,同样的规则不适用于UNIQUE。我必须承认我几乎从不处理复合 PK,但感谢您的纠正。希望这些信息将在未来对其他人有所帮助:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-12
  • 2013-08-17
  • 2016-11-28
  • 2013-07-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多