Reputation: 41
I have this stored procedure in MySQL version 5.7. If I want to create n elements it would be much faster to insert n elements in one statement two times rather than call the stored procedure n times.
How can I create a stored procedure that takes a "list" of names, a team id and does this?
CREATE PROCEDURE create_data_user(IN name VARCHAR(100), IN data_user_team_id INT)
BEGIN
START TRANSACTION;
INSERT INTO users (users.name, users.type)
VALUES (name, "team_data");
INSERT INTO team_members (team_id, user_id, mod_time)
VALUES (data_user_team_id, LAST_INSERT_ID(), UNIX_TIMESTAMP());
COMMIT;
END ;;
A stored procedure that creates two elements would look like this:
CREATE PROCEDURE create_data_user(IN name VARCHAR(100), IN name2 VARCHAR(100), IN
data_user_team_id INT)
BEGIN
START TRANSACTION;
INSERT INTO users (users.name, users.type)
VALUES
(name, "team_data"),
(name2, "team_data");
INSERT INTO team_members (team_id, user_id, mod_time)
VALUES
(data_user_team_id, LAST_INSERT_ID(), UNIX_TIMESTAMP()),
(data_user_team_id, LAST_INSERT_ID()+1, UNIX_TIMESTAMP());
COMMIT;
END ;;
Edit: There are different ways to tackle this. You could just scrap the SP and copy-paste batch insert code. Rick James presented a complex solution, but I think you can do something simpler, perhaps at some cost in performance (but better than many individual inserts).
On the caller side you do something like this:
CREATE TEMPORARY TABLE names (name);
INSERT INTO names
VALUES
(name1),
(name2),
...;
CALL create_data_users(1);
And then the stored procedure is like this:
CREATE PROCEDURE create_data_users(IN data_user_team_id INT)
BEGIN
START TRANSACTION;
INSERT INTO users (users.name, users.type)
SELECT name, "team_data" FROM names;
SET @num=LAST_INSERT_ID();
INSERT INTO team_members (team_id, user_id, mod_time)
SELECT data_user_team_id, @num:=@num+1, UNIX_TIMESTAMP() FROM names;
COMMIT;
END ;;
Upvotes: 0
Views: 2525
Reputation: 142278
The best efficient generalization, especially for long lists, I have found is to
INSERT
to populate the tableINSERT ... SELECT ...
to get the items in the real table(No loops involved.)
Specifics: http://mysql.rjweb.org/doc.php/staging_table#normalization
(That is focused around the very likely situation where the names are already in the table. However, it should work fine for your case.)
Upvotes: 1
Reputation: 42622
CREATE PROCEDURE create_data_users (IN users_list TEXT, IN data_user_team_id INT)
BEGIN
DECLARE name VARCHAR(255);
REPEAT
SET name = TRIM(SUBSTRING_INDEX(users_list, ',', 1));
SET users_list = CASE WHEN LOCATE(',', users_list)
THEN TRIM(SUBSTRING(users_list FROM 1 + LOCATE(',', users_list)))
ELSE '' END;
INSERT INTO users (users.name, users.type)
VALUES (name, "team_data");
INSERT INTO team_members (team_id, user_id, mod_time)
VALUES (data_user_team_id, LAST_INSERT_ID(), UNIX_TIMESTAMP());
UNTIL users_list = '' END REPEAT;
END
https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=37e397c1066e1e8459df70fc6131e5d4
Upvotes: 0