使用 table 字段作为存储过程参数(将给定的 table 字段重新分配到其他 table 中)
Use table fields as stored procedure parameters (to redistribute a given table fields into other tables)
我有以下table的结构:
ITEMS:
╔═══════════╤══════════════╤══════╤═════╤═════════╤════════════════╗
║ FIELD │ TYPE │ NULL │ KEY │ DEFAULT │ EXTRA ║
╠═══════════╪══════════════╪══════╪═════╪═════════╪════════════════╣
║ id │ int │ NO │ PRI │ │ auto_increment ║
╟───────────┼──────────────┼──────┼─────┼─────────┼────────────────╢
║ image_url │ varchar(255) │ NO │ │ │ ║
╚═══════════╧══════════════╧══════╧═════╧═════════╧════════════════╝
ITEM_TRANSLATIONS:
╔═════════════╤══════════════╤══════╤═════╤═════════╤════════════════╗
║ FIELD │ TYPE │ NULL │ KEY │ DEFAULT │ EXTRA ║
╠═════════════╪══════════════╪══════╪═════╪═════════╪════════════════╣
║ id │ int │ NO │ PRI │ │ auto_increment ║
╟─────────────┼──────────────┼──────┼─────┼─────────┼────────────────╢
║ description │ varchar(255) │ NO │ │ │ ║
╟─────────────┼──────────────┼──────┼─────┼─────────┼────────────────╢
║ title │ varchar(45) │ NO │ │ │ ║
╚═════════════╧══════════════╧══════╧═════╧═════════╧════════════════╝
我还有一个存储过程,可以通过这种方式将其参数重新分配给所需的 table:
DELIMITER //
DROP PROCEDURE IF EXISTS addItem //
CREATE PROCEDURE addItem (
IN _item__image_url VARCHAR(255),
IN _item_translations__title VARCHAR(45),
IN _item_translations__description VARCHAR(255)
)
BEGIN
START TRANSACTION;
INSERT INTO item (
image_url
)
VALUES (
_item__image_url
);
INSERT INTO item_translations (
item_id,
title,
`description`
)
VALUES (
LAST_INSERT_ID(),
_item_translations__title,
_item_translations__description
);
COMMIT ;
END //
DELIMITER ;
如果我这样调用这个过程:
CALL addBrand(
"/images/items.png",
"My Item",
"An oversimplified item just for this question."
);
我得到了预期的结果:
ITEMS:
╔════╤═══════════════════╗
║ ID │ IMAGE_URL ║
╠════╪═══════════════════╣
║ 19 │ /images/items.png ║
╚════╧═══════════════════╝
ITEM_TRANSLATIONS:
╔════╤═════════╤═════════╤════════════════════════════════════════════════╗
║ ID │ ITEM_ID │ TITLE │ DESCRIPTION ║
╠════╪═════════╪═════════╪════════════════════════════════════════════════╣
║ 7 │ 19 │ My Item │ An oversimplified item just for this question. ║
╚════╧═════════╧═════════╧════════════════════════════════════════════════╝
我有第三个 table,其中 N 行包含所有必填字段:
IMPORTED_TABLE
╔════╤══════════════╤══════════════════════════════════╤════════════════════════╗
║ ID │ TITLE │ DESCRIPTION │ IMAGE_URL ║
╠════╪══════════════╪══════════════════════════════════╪════════════════════════╣
║ 42 │ Another Item │ Yet another oversimplified item. │ /images/items_2.png ║
╟────┼──────────────┼──────────────────────────────────┼────────────────────────╢
║ 43 │ This Item │ A nice item │ /images/thanks.png ║
╟────┼──────────────┼──────────────────────────────────┼────────────────────────╢
║ 44 │ Trixie Item │ The great and powerful item! │ /images/mlp/trixie.png ║
╚════╧══════════════╧══════════════════════════════════╧════════════════════════╝
如何使用此 table 内容作为存储过程的参数,以便能够根据需要填充所需的 table?
为了得到这个:
ITEMS:
╔════╤════════════════════════╗
║ ID │ IMAGE_URL ║
╠════╪════════════════════════╣
║ 19 │ /images/items.png ║
╟────┼────────────────────────╢
║ 20 │ /images/items_2.png ║
╟────┼────────────────────────╢
║ 21 │ /images/thanks.png ║
╟────┼────────────────────────╢
║ 22 │ /images/mlp/trixie.png ║
╚════╧════════════════════════╝
ITEM_TRANSLATIONS
╔════╤═════════╤══════════════╤════════════════════════════════════════════════╗
║ ID │ ITEM_ID │ TITLE │ DESCRIPTION ║
╠════╪═════════╪══════════════╪════════════════════════════════════════════════╣
║ 7 │ 19 │ My Item │ An oversimplified item just for this question. ║
╟────┼─────────┼──────────────┼────────────────────────────────────────────────╢
║ 8 │ 20 │ Another Item │ Yet another oversimplified item. ║
╟────┼─────────┼──────────────┼────────────────────────────────────────────────╢
║ 9 │ 21 │ This Item │ A nice item ║
╟────┼─────────┼──────────────┼────────────────────────────────────────────────╢
║ 10 │ 22 │ Trixie Item │ The great and powerful item! ║
╚════╧═════════╧══════════════╧════════════════════════════════════════════════╝
显然这是一个过于简单化的示例。在存储过程中,所有参数都有不同的数据处理方式,所以我不必重新创建存储过程。
IMPORTED_TABLE
中的 ID
值是否应该用于 ITEMS
中的 ID
?
如果是这样,那么您可以这样做:
START TRANSACTION;
INSERT INTO ITEMS (ID, IMAGE_URL)
SELECT ID, IMAGE_URL FROM IMPORTED_TABLE;
INSERT INTO ITEM_TRANSLATIONS (ITEM_ID, TITLE, DESCRIPTION)
SELECT ID, TITLE, DESCRIPTION FROM IMPORTED_TABLE;
COMMIT;
这将对 ITEMS.ID
和 ITEM_TRANSLATIONS.ITEM_ID
逐字使用 ID
值。
但是,如果您想插入 URL 并忽略导入数据中的 ID
值,并让 ITEMS
table 生成新的 ID 值,那么您可以这样做它在一个批次中,并假设该批次是一组连续的值。
START TRANSACTION;
INSERT INTO ITEMS (IMAGE_URL)
SELECT IMAGE_URL FROM IMPORTED_TABLE;
SET @START_ID = LAST_INSERT_ID() - 1;
INSERT INTO ITEM_TRANSLATIONS (ITEM_ID, TITLE, DESCRIPTION)
SELECT (@START_ID := @START_ID+1), TITLE, DESCRIPTION FROM IMPORTED_TABLE;
COMMIT;
假设这些值是连续的是否安全?默认情况下,是的,它是安全的。例如,MySQL 的 JDBC 驱动程序在您进行批量插入时做出此假设,因此它可以 return 生成的 ID 值集。
例外情况是,如果您在 MySQL 实例上设置了 innodb_autoinc_lock_mode=2
选项,则不保证这些值是连续的。这不是默认设置,因此它可能不适用于您的情况。
(阅读 https://dev.mysql.com/doc/refman/8.0/en/innodb-auto-increment-handling.html 了解详情)
(代表问题作者发布了答案改进,以便将其移动到答案space).
感谢接受的答案,我能够解决这个挑战。然而,auto_increment
值增加了行数 inserted/read(可能是因为 MySQL 中的错误,如评论中所述)。
所以我需要创建另一个存储过程来获取最大 ID 值并使用它来更改所有涉及的 table。此存储过程如下:
DELIMITER //
DROP PROCEDURE IF EXISTS tableMaxID //
CREATE PROCEDURE tableMaxID(IN nameOfTable VARCHAR(20))
BEGIN
SET @qry=CONCAT('SELECT MAX(id) INTO @maxIdValue FROM ', nameOfTable);
PREPARE st FROM @qry;
EXECUTE st;
DEALLOCATE PREPARE st;
SET @maxIdValue := @maxIdValue + 1;
END //
DELIMITER ;
然后,我将此修复程序添加到每个涉及的原始存储过程中 table:
DELIMITER //
DROP PROCEDURE IF EXISTS addItem //
CREATE PROCEDURE addItem ()
BEGIN
START TRANSACTION;
/* INSERT INTO the corresponding tables */
INSERT INTO items (image_url)
SELECT CONCAT(`items.image_url`, ' testing') FROM imported_table;
SET @START_ID = LAST_INSERT_ID() - 1;
INSERT INTO items_translations (item_id, title, `description`)
SELECT (@START_ID := @START_ID+1), `items_translations.title`, `brands_translations.description` FROM imported_table;
/***********/
/* Fix brands auto_increment */
CALL tableMaxID('items');
SET @qry=CONCAT('ALTER TABLE items AUTO_INCREMENT =', @maxIdValue);
PREPARE st FROM @qry;
EXECUTE st;
DEALLOCATE PREPARE st;
/* Fix items_translations auto_increment */
CALL tableMaxID('items_translations');
SET @qry=CONCAT('ALTER TABLE items_translations AUTO_INCREMENT =', @maxIdValue);
PREPARE st FROM @qry;
EXECUTE st;
DEALLOCATE PREPARE st;
COMMIT;
END //
DELIMITER ;
现在,只需调用存储过程,将给定的数据插入相应的 tables,用正确的 auto_increment
修复涉及的 tables值:
CALL addBrand();
我有以下table的结构:
ITEMS:
╔═══════════╤══════════════╤══════╤═════╤═════════╤════════════════╗
║ FIELD │ TYPE │ NULL │ KEY │ DEFAULT │ EXTRA ║
╠═══════════╪══════════════╪══════╪═════╪═════════╪════════════════╣
║ id │ int │ NO │ PRI │ │ auto_increment ║
╟───────────┼──────────────┼──────┼─────┼─────────┼────────────────╢
║ image_url │ varchar(255) │ NO │ │ │ ║
╚═══════════╧══════════════╧══════╧═════╧═════════╧════════════════╝
ITEM_TRANSLATIONS:
╔═════════════╤══════════════╤══════╤═════╤═════════╤════════════════╗
║ FIELD │ TYPE │ NULL │ KEY │ DEFAULT │ EXTRA ║
╠═════════════╪══════════════╪══════╪═════╪═════════╪════════════════╣
║ id │ int │ NO │ PRI │ │ auto_increment ║
╟─────────────┼──────────────┼──────┼─────┼─────────┼────────────────╢
║ description │ varchar(255) │ NO │ │ │ ║
╟─────────────┼──────────────┼──────┼─────┼─────────┼────────────────╢
║ title │ varchar(45) │ NO │ │ │ ║
╚═════════════╧══════════════╧══════╧═════╧═════════╧════════════════╝
我还有一个存储过程,可以通过这种方式将其参数重新分配给所需的 table:
DELIMITER //
DROP PROCEDURE IF EXISTS addItem //
CREATE PROCEDURE addItem (
IN _item__image_url VARCHAR(255),
IN _item_translations__title VARCHAR(45),
IN _item_translations__description VARCHAR(255)
)
BEGIN
START TRANSACTION;
INSERT INTO item (
image_url
)
VALUES (
_item__image_url
);
INSERT INTO item_translations (
item_id,
title,
`description`
)
VALUES (
LAST_INSERT_ID(),
_item_translations__title,
_item_translations__description
);
COMMIT ;
END //
DELIMITER ;
如果我这样调用这个过程:
CALL addBrand(
"/images/items.png",
"My Item",
"An oversimplified item just for this question."
);
我得到了预期的结果:
ITEMS:
╔════╤═══════════════════╗
║ ID │ IMAGE_URL ║
╠════╪═══════════════════╣
║ 19 │ /images/items.png ║
╚════╧═══════════════════╝
ITEM_TRANSLATIONS:
╔════╤═════════╤═════════╤════════════════════════════════════════════════╗
║ ID │ ITEM_ID │ TITLE │ DESCRIPTION ║
╠════╪═════════╪═════════╪════════════════════════════════════════════════╣
║ 7 │ 19 │ My Item │ An oversimplified item just for this question. ║
╚════╧═════════╧═════════╧════════════════════════════════════════════════╝
我有第三个 table,其中 N 行包含所有必填字段:
IMPORTED_TABLE
╔════╤══════════════╤══════════════════════════════════╤════════════════════════╗
║ ID │ TITLE │ DESCRIPTION │ IMAGE_URL ║
╠════╪══════════════╪══════════════════════════════════╪════════════════════════╣
║ 42 │ Another Item │ Yet another oversimplified item. │ /images/items_2.png ║
╟────┼──────────────┼──────────────────────────────────┼────────────────────────╢
║ 43 │ This Item │ A nice item │ /images/thanks.png ║
╟────┼──────────────┼──────────────────────────────────┼────────────────────────╢
║ 44 │ Trixie Item │ The great and powerful item! │ /images/mlp/trixie.png ║
╚════╧══════════════╧══════════════════════════════════╧════════════════════════╝
如何使用此 table 内容作为存储过程的参数,以便能够根据需要填充所需的 table? 为了得到这个:
ITEMS:
╔════╤════════════════════════╗
║ ID │ IMAGE_URL ║
╠════╪════════════════════════╣
║ 19 │ /images/items.png ║
╟────┼────────────────────────╢
║ 20 │ /images/items_2.png ║
╟────┼────────────────────────╢
║ 21 │ /images/thanks.png ║
╟────┼────────────────────────╢
║ 22 │ /images/mlp/trixie.png ║
╚════╧════════════════════════╝
ITEM_TRANSLATIONS
╔════╤═════════╤══════════════╤════════════════════════════════════════════════╗
║ ID │ ITEM_ID │ TITLE │ DESCRIPTION ║
╠════╪═════════╪══════════════╪════════════════════════════════════════════════╣
║ 7 │ 19 │ My Item │ An oversimplified item just for this question. ║
╟────┼─────────┼──────────────┼────────────────────────────────────────────────╢
║ 8 │ 20 │ Another Item │ Yet another oversimplified item. ║
╟────┼─────────┼──────────────┼────────────────────────────────────────────────╢
║ 9 │ 21 │ This Item │ A nice item ║
╟────┼─────────┼──────────────┼────────────────────────────────────────────────╢
║ 10 │ 22 │ Trixie Item │ The great and powerful item! ║
╚════╧═════════╧══════════════╧════════════════════════════════════════════════╝
显然这是一个过于简单化的示例。在存储过程中,所有参数都有不同的数据处理方式,所以我不必重新创建存储过程。
IMPORTED_TABLE
中的 ID
值是否应该用于 ITEMS
中的 ID
?
如果是这样,那么您可以这样做:
START TRANSACTION;
INSERT INTO ITEMS (ID, IMAGE_URL)
SELECT ID, IMAGE_URL FROM IMPORTED_TABLE;
INSERT INTO ITEM_TRANSLATIONS (ITEM_ID, TITLE, DESCRIPTION)
SELECT ID, TITLE, DESCRIPTION FROM IMPORTED_TABLE;
COMMIT;
这将对 ITEMS.ID
和 ITEM_TRANSLATIONS.ITEM_ID
逐字使用 ID
值。
但是,如果您想插入 URL 并忽略导入数据中的 ID
值,并让 ITEMS
table 生成新的 ID 值,那么您可以这样做它在一个批次中,并假设该批次是一组连续的值。
START TRANSACTION;
INSERT INTO ITEMS (IMAGE_URL)
SELECT IMAGE_URL FROM IMPORTED_TABLE;
SET @START_ID = LAST_INSERT_ID() - 1;
INSERT INTO ITEM_TRANSLATIONS (ITEM_ID, TITLE, DESCRIPTION)
SELECT (@START_ID := @START_ID+1), TITLE, DESCRIPTION FROM IMPORTED_TABLE;
COMMIT;
假设这些值是连续的是否安全?默认情况下,是的,它是安全的。例如,MySQL 的 JDBC 驱动程序在您进行批量插入时做出此假设,因此它可以 return 生成的 ID 值集。
例外情况是,如果您在 MySQL 实例上设置了 innodb_autoinc_lock_mode=2
选项,则不保证这些值是连续的。这不是默认设置,因此它可能不适用于您的情况。
(阅读 https://dev.mysql.com/doc/refman/8.0/en/innodb-auto-increment-handling.html 了解详情)
(代表问题作者发布了答案改进,以便将其移动到答案space).
感谢接受的答案,我能够解决这个挑战。然而,auto_increment
值增加了行数 inserted/read(可能是因为 MySQL 中的错误,如评论中所述)。
所以我需要创建另一个存储过程来获取最大 ID 值并使用它来更改所有涉及的 table。此存储过程如下:
DELIMITER //
DROP PROCEDURE IF EXISTS tableMaxID //
CREATE PROCEDURE tableMaxID(IN nameOfTable VARCHAR(20))
BEGIN
SET @qry=CONCAT('SELECT MAX(id) INTO @maxIdValue FROM ', nameOfTable);
PREPARE st FROM @qry;
EXECUTE st;
DEALLOCATE PREPARE st;
SET @maxIdValue := @maxIdValue + 1;
END //
DELIMITER ;
然后,我将此修复程序添加到每个涉及的原始存储过程中 table:
DELIMITER //
DROP PROCEDURE IF EXISTS addItem //
CREATE PROCEDURE addItem ()
BEGIN
START TRANSACTION;
/* INSERT INTO the corresponding tables */
INSERT INTO items (image_url)
SELECT CONCAT(`items.image_url`, ' testing') FROM imported_table;
SET @START_ID = LAST_INSERT_ID() - 1;
INSERT INTO items_translations (item_id, title, `description`)
SELECT (@START_ID := @START_ID+1), `items_translations.title`, `brands_translations.description` FROM imported_table;
/***********/
/* Fix brands auto_increment */
CALL tableMaxID('items');
SET @qry=CONCAT('ALTER TABLE items AUTO_INCREMENT =', @maxIdValue);
PREPARE st FROM @qry;
EXECUTE st;
DEALLOCATE PREPARE st;
/* Fix items_translations auto_increment */
CALL tableMaxID('items_translations');
SET @qry=CONCAT('ALTER TABLE items_translations AUTO_INCREMENT =', @maxIdValue);
PREPARE st FROM @qry;
EXECUTE st;
DEALLOCATE PREPARE st;
COMMIT;
END //
DELIMITER ;
现在,只需调用存储过程,将给定的数据插入相应的 tables,用正确的 auto_increment
修复涉及的 tables值:
CALL addBrand();