【问题标题】:How to insert data to multiple tables with foreign key dependencies involved (MySQL)如何将数据插入到涉及外键依赖的多个表中(MySQL)
【发布时间】:2013-08-05 22:50:18
【问题描述】:

我正在寻找将数据插入多个 MySQL 表的最佳实践方法,其中某些列是外键依赖项。这是一个例子:

Table: contacts
--------------------------------------------------------------------
|  contact_id  |  first_name  | last_name  |  prof_id  |  zip_code  |
--------------------------------------------------------------------

'contacts' 表有 PRIMARY KEY (contact_id),它只是 auto_increments,和 FOREIGN KEY (prof_id) REFERENCES 'profession' 表,FOREIGN KEY (zip_code) REFERENCES 'zip_code' 表。这些表看起来像这样:

Table: profession
----------------------------
|  prof_id  |  profession  |
----------------------------

其中 'prof_id' 是一个 INT NOT NULL AUTO_INCREMENT PRIMARY KEY,并且

Table: zip_code
--------------------------------
|  zip_code  | city  |  state  |
--------------------------------

其中 'zip_code' 是一个 INT(5) NOT NULL PRIMARY KEY。

我想为一个新人添加记录,比如说:

first_name = 'John', last_name = 'Doe', profession = 'Network Administrator', city = 'Sometown', state = 'NY', zip_code = 12345

这就是我想要做的:我想获取该信息并将其插入到适当的表和列中。为了防止列中的重复值(例如专业),我首先要确保没有“网络管理员”的条目,如果有,我只想获取它的键值,如果不插入它然后获取它的键值。 zip_code、city、state 也是如此——如果存在,只需使用该 zip_code 密钥,否则插入新数据并获取关联的密钥。然后,最后,我想使用提供的信息将新联系人输入到“联系人”表中,包括与其他表中的职业和位置相关的适当键值。

我的问题是,最好的推荐方法是什么?我知道我可以坐在这里写一个语句来检查给定的职业是否存在,如果不存在则输入它,然后获取密钥。对 zip_code 执行相同的操作。然后最后将所有这些插入到联系人中,但是我知道必须有更好的方法在更少(也许是一个)语句中完成此操作,特别是考虑到如果数据库在中间脱机一会儿可能会导致问题所有这一切。有没有办法使用 JOIN 和这个 INSERT 来让所有的东西都级联到正确的位置?我是否应该使用 TRANSACTION 系列语句来处理这个问题?

我正处于 SQL 的学习阶段,但我觉得到目前为止我使用的书籍和资源已经开始使用嵌套查询和 JOINS,前提是我们已经填充了所有这些数据表。我什至愿意接受关于我应该在谷歌上搜索什么以更好地学习这一点的建议,或者任何可以帮助填补这一空白的资源。理想情况下,我希望看到一些功能正常的 SQL 代码来执行此操作。如有必要,假设 PHP 作为与数据库交互的语言,但命令行 sql 是我的目标。提前谢谢,希望我把一切都说清楚了。

【问题讨论】:

  • 你应该学习ORM。我正在使用 Doctrine 2.2。通过使用 ORM,您将能够插入/更新/删除,而 Doctrine 将处理所有关系。你想必须手动做任何事情。教义是使用对象。 Doctrine 将为您生成所有模型类。
  • 我知道 ORM 肯定会很有价值,所以我感谢您提供的信息。但是,我想首先直接使用 SQL 从根本上了解它是如何工作的,@seanmk 在下面为我回答了这个问题。无论哪种方式,我认为您的信息可能对其他遇到此问题的人有用,所以我也给它一个 +1。

标签: php mysql sql


【解决方案1】:

简而言之,您想使用transactions (more doc on this) 以便您的插入是atomic。这是保证插入所有(或不插入)数据的唯一方法。否则,您可能会遇到您描述的数据库在某些插入后变得不可用而其他无法完成的情况。事务告诉数据库您正在做的事情是全有或全无,因此如果出现问题,它应该回滚。

当您使用合成主键时,PHP 和其他语言提供了获取最后插入的 id 的机制。如果你想完全在 MySQL 中完成,你可以使用 LAST_INSERT_ID() 函数。你最终会得到这样的代码:

START TRANSACTION;
INSERT INTO foo (auto,text)
    VALUES(NULL,'text');         # generate ID by inserting NULL
INSERT INTO foo2 (id,text)
    VALUES(LAST_INSERT_ID(),'text');  # use ID in second table
COMMIT;

【讨论】:

  • 感谢您快速简洁的回复。我还刚刚阅读了在 MySQL 中使用变量的内容,我认为这对我有帮助,因为我需要跟踪多个先前的插入 id 值,而不仅仅是前一个。进一步阅读使我相信我需要执行“INSERT IGNORE INTO ...”或“INSERT ... ON DUPLICATE KEY UPDATE”之类的操作来检查给定列中的现有值并避免重复信息 - 这听起来关于你的权利?
  • 是的,但要小心,因为 INSERT ... ON DUPLICATE KEY UPDATE 会锁定您尝试插入的整个表,因此使用它会导致大量数据库争用,因为其他请求必须等待让他们完成。另一方面,此处讨论的 INSERT IGNORE 存在问题:stackoverflow.com/questions/548541/…
猜你喜欢
  • 2010-12-01
  • 1970-01-01
  • 2014-11-21
  • 1970-01-01
  • 2018-08-07
  • 1970-01-01
  • 1970-01-01
  • 2019-09-09
  • 2017-12-14
相关资源
最近更新 更多