如果不存在,则插入一对多关系(在单个查询中)?

时间:2014-03-16 09:20:18

标签: mysql sql

考虑以下表格:

产品

+----+------+-------------+
| id | name | category_id |
+----+------+-------------+
| 1  | foo  |           1 |
+----+------+-------------+

类别

+----+------+
| id | name |
+----+------+
| 1  | food |
+----+------+

现在假设我有人发布了一个新产品:

{
  "name": "bar",
  "category": "drink"
}

在这种情况下,我们需要自动创建新类别:

INSERT IGNORE INTO categories (name) VALUES ('drink')

然后我们最终可以插入实际的产品行:

INSERT INTO products (name, category_id) VALUES ('bar', SELECT id FROM categories WHERE name = 'drink')

然而,虽然这有效,但它需要一个事务设置是安全的,因为这似乎不是一个超级复杂的查询,我想知道是否可以将两个查询合并在一起(例如,将类别查询插入到产品插入的选择子查询中?

2 个答案:

答案 0 :(得分:2)

我会反对INSERT IGNORE,原因是@Bill Karwin so eloquently explains。此外,正如INSERT ... ON DUPLICATE KEY UPDATE Syntax所述:

  

如果表包含AUTO_INCREMENT列并且INSERT ... ON DUPLICATE KEY UPDATE插入或更新行,则LAST_INSERT_ID()函数将返回AUTO_INCREMENT值。例外:对于更新,LAST_INSERT_ID()在MySQL 5.1.12之前没有意义。但是,您可以使用LAST_INSERT_ID(expr)解决此问题。假设idAUTO_INCREMENT列。要使LAST_INSERT_ID()对更新有意义,请按如下方式插入行:

INSERT INTO table (a,b,c) VALUES (1,2,3)
  ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), c=3;

然后可以获得How to Get the Unique ID for the Last Inserted Row下记录的id(无论是预先存在的还是新插入的):

  

如果将记录插入包含AUTO_INCREMENT列的表中,则可以通过调用mysql_insert_id()函数获取存储在该列中的值。

[ deletia ]
     

当生成新的AUTO_INCREMENT值时,您还可以通过执行带有mysql_query()SELECT LAST_INSERT_ID()语句并从语句返回的结果集中检索值来获取它。 / p>

因此,例如,人们可以这样做:

INSERT INTO categories (name) VALUES ('drink')
  ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id);

INSERT INTO products (name, category_id) VALUES ('bar', LAST_INSERT_ID());

当然,如果您需要原子性,这些语句仍然需要在事务中执行。

答案 1 :(得分:-1)

不,那是不可能的。但是,您可以执行的操作是在产品表上创建BEFORE INSERT触发器,并在触发器内部检查(如果类别已存在)。如果它不存在,你可以在那里创建它。

触发器将在与INSERT - 语句相同的事务中自动执行,因此不需要额外的事务处理。

我看到的唯一问题是,当您忘记触发器时,您可能会开始想知道为什么每个新产品都会自动显示类别(类似于我)。

<强>更新

您可以在MySQL Documentation

中查看简单触发器的示例

您可以使用BEFORE INSERTNEW.column_name触发器中访问要插入的新值,这样就可以NEW.category