"Insert...select" 具有多个值和规范化数据库的事务
"Insert...select" transactions with multiple values and normalized database
This question 正确解释了如何在数据库中为 "hierarchical" 结构(is-a 关系)同时插入数据:
No, you can't insert into multiple tables in one MySQL command. You
can however use transactions.
BEGIN;
INSERT INTO base_class (data0, data1) VALUES('0', '1');
INSERT INTO derived_class (base_id, data2, data3) VALUES(LAST_INSERT_ID(), '2', '3');
COMMIT;
该解决方案在一次插入一个东西时效果很好。
但是,我需要使用 INSERT...SELECT
.
同时插入多个值
BEGIN;
INSERT INTO base_class (data0, data1) SELECT d0, d1 FROM stuff
INSERT INTO derived_class (base_ids, data2, data3) SELECT ???, d2, d3 FROM stuff
COMMIT;
我应该如何告诉 MySQL 到 "link" derived_class
的每个实例到之前通过基础 class ID 创建的 base_class
?
理想情况下,我会 "loop" 同时通过两个表,但这在 MySQL 或 MariaDB 中是不可能的:
# PSEUDOCODE! NOT VALID.
BEGIN;
INSERT INTO
base_class (data0, data1)
ALONG_WITH derived_class (base_ids, data2, data3)
SELECT d0, d1, GET_ALONG_FIELD(base_class, id), d2, d3 FROM stuff
# _______ table 1 values
# _______________________________________ table 2 values
COMMIT;
如何在保持表格的 "hierarchical" 设计的同时解决这个问题?
编辑:
我再次打开了这个问题,因为我很好奇是否有可能实现我想要的行为而不必诉诸类似程序的 SQL 代码(使用游标)。
有没有不用游标解决这个问题的方法?
我不太确定我理解你的问题。我认为您正在尝试将 d0
和 d1
插入 base_class
并将 base_ids
、d2
和 d3
插入 derived_class
以相同的顺序,以便 base_class
和 derived_class
中的第 n 个插入值都来自 stuff
中的第 n 个记录。如果我的理解是正确的,下面的交易就如你所愿。
BEGIN;
INSERT INTO base_class (data0, data1)
SELECT d0, d1
FROM stuff
ORDER BY base_ids
INSERT INTO derived_class (base_ids, data2, data3)
SELECT base_ids, d2, d3
FROM stuff
ORDER BY base_ids
COMMIT;
游标应该可以解决问题。您可以遍历 stuff
table 并一次执行一个插入,并在执行过程中获取插入 ID。像这样的东西(未经测试):
BEGIN;
DECLARE get_stuff CURSOR FOR SELECT id FROM stuff;
DECLARE current_id INT;
OPEN get_stuff;
insert_stuff: LOOP
FETCH get_stuff INTO current_id;
INSERT INTO base_class (data0, data1)
SELECT d0, d1 FROM stuff WHERE id = current_id
INSERT INTO derived_class (base_ids, data2, data3)
SELECT mysql_insert_id(), d2, d3 FROM stuff WHERE id = current_id
END LOOP insert_stuff;
CLOSE get_stuff;
COMMIT;
另一种可能的方法是在两个 "insert" table 上创建一个视图。根据您的 table 的结构,插入视图可能会受到限制,但这样的事情可能有效(也未测试):
CREATE VIEW stuff_view AS
SELECT b.data0, b.data1, d.data2, d.data3 FROM base_class AS b
INNER JOIN dervied_class AS d ON (d.base_id = b.id)
INSERT INTO stuff_view (data0, data1, data2, data3)
SELECT d0, d1, d2, d3 FROM stuff
我实际上不确定 MySQL 是否会自动为基础和派生的 ID 分配适当的 ID class tables。
This question 正确解释了如何在数据库中为 "hierarchical" 结构(is-a 关系)同时插入数据:
No, you can't insert into multiple tables in one MySQL command. You can however use transactions.
BEGIN; INSERT INTO base_class (data0, data1) VALUES('0', '1'); INSERT INTO derived_class (base_id, data2, data3) VALUES(LAST_INSERT_ID(), '2', '3'); COMMIT;
该解决方案在一次插入一个东西时效果很好。
但是,我需要使用 INSERT...SELECT
.
BEGIN;
INSERT INTO base_class (data0, data1) SELECT d0, d1 FROM stuff
INSERT INTO derived_class (base_ids, data2, data3) SELECT ???, d2, d3 FROM stuff
COMMIT;
我应该如何告诉 MySQL 到 "link" derived_class
的每个实例到之前通过基础 class ID 创建的 base_class
?
理想情况下,我会 "loop" 同时通过两个表,但这在 MySQL 或 MariaDB 中是不可能的:
# PSEUDOCODE! NOT VALID.
BEGIN;
INSERT INTO
base_class (data0, data1)
ALONG_WITH derived_class (base_ids, data2, data3)
SELECT d0, d1, GET_ALONG_FIELD(base_class, id), d2, d3 FROM stuff
# _______ table 1 values
# _______________________________________ table 2 values
COMMIT;
如何在保持表格的 "hierarchical" 设计的同时解决这个问题?
编辑:
我再次打开了这个问题,因为我很好奇是否有可能实现我想要的行为而不必诉诸类似程序的 SQL 代码(使用游标)。
有没有不用游标解决这个问题的方法?
我不太确定我理解你的问题。我认为您正在尝试将 d0
和 d1
插入 base_class
并将 base_ids
、d2
和 d3
插入 derived_class
以相同的顺序,以便 base_class
和 derived_class
中的第 n 个插入值都来自 stuff
中的第 n 个记录。如果我的理解是正确的,下面的交易就如你所愿。
BEGIN;
INSERT INTO base_class (data0, data1)
SELECT d0, d1
FROM stuff
ORDER BY base_ids
INSERT INTO derived_class (base_ids, data2, data3)
SELECT base_ids, d2, d3
FROM stuff
ORDER BY base_ids
COMMIT;
游标应该可以解决问题。您可以遍历 stuff
table 并一次执行一个插入,并在执行过程中获取插入 ID。像这样的东西(未经测试):
BEGIN;
DECLARE get_stuff CURSOR FOR SELECT id FROM stuff;
DECLARE current_id INT;
OPEN get_stuff;
insert_stuff: LOOP
FETCH get_stuff INTO current_id;
INSERT INTO base_class (data0, data1)
SELECT d0, d1 FROM stuff WHERE id = current_id
INSERT INTO derived_class (base_ids, data2, data3)
SELECT mysql_insert_id(), d2, d3 FROM stuff WHERE id = current_id
END LOOP insert_stuff;
CLOSE get_stuff;
COMMIT;
另一种可能的方法是在两个 "insert" table 上创建一个视图。根据您的 table 的结构,插入视图可能会受到限制,但这样的事情可能有效(也未测试):
CREATE VIEW stuff_view AS
SELECT b.data0, b.data1, d.data2, d.data3 FROM base_class AS b
INNER JOIN dervied_class AS d ON (d.base_id = b.id)
INSERT INTO stuff_view (data0, data1, data2, data3)
SELECT d0, d1, d2, d3 FROM stuff
我实际上不确定 MySQL 是否会自动为基础和派生的 ID 分配适当的 ID class tables。