简体   繁体   中英

Pass list of values to be inserted as parameter to stored procedure

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 ;;

Using a similar structure as Akina's solution, but where I build two SQL strings I get this. The problems with it are what if a name contains a comma in it? And just escaping special symbols in general, it seems it gives me a syntax error when I escape special symbols on each name beforehand (I do this in PHP using mysqli escape_string, if relevant) and when I don't. For example CALL create_data_users('O\\'brien', 1) won't work and in CALL create_data_users('jo,hn, jane', 1) "jo,hn" will be interpreted as two users.

CREATE PROCEDURE create_data_users (IN users_list TEXT, IN 

data_user_team_id INT)
BEGIN
START TRANSACTION;
    SET @s1 = "INSERT INTO users (name, type) VALUES ";
    SET @s2 = "INSERT INTO team_members (team_id, user_id, mod_time) VALUES ";
    SET @i = 0;
    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;
        SET @s1 = CONCAT(@s1, "('", @name, "','team_data')");
        SET @s2 = CONCAT(@s2, "(", data_user_team_id, ", LAST_INSERT_ID()+", @i, ", UNIX_TIMESTAMP())");
        IF users_list <> '' THEN
            SET @s1 = CONCAT(@s1, ",");
            SET @s2 = CONCAT(@s2, ",");
        END IF;
        SET @i = @i + 1;
    UNTIL users_list = '' END REPEAT;
    PREPARE stmt1 FROM @s1;
    EXECUTE stmt1;
    PREPARE stmt2 FROM @s2;
    EXECUTE stmt2;
COMMIT;
END ;;
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

The best efficient generalization, especially for long lists, I have found is to

  1. Build a temp table
  2. Use a batch INSERT to populate the table
  3. INSERT ... SELECT ... to get the items in the real table
  4. Do a complex update with a join to pull back all the ids.

(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.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM