2016-02-03 41 views
1

如何编写MySQL存储过程以插入可变大小列表中的值?更具体地说,我需要将数据插入到一个父表中,从插入中获取ID,然后将可变数量的子记录与新ID一起插入另一个一对多关系表中。我的模式看起来是这样的:MySQL存储过程从列表中插入多行

表A:

table_a_id -- Auto Increment 
counter 
some_data... 

表B:

table_b_id -- Auto Increment 
table_a_id -- Foreign Key Constraint 
some_data_from_list... 

我的存储过程,到目前为止是这样的:

DELIMITER ;; 
CREATE PROCEDURE insert_group_alert(
    IN _some_data_a   VARCHAR(255), 
    IN _data_list_b   TEXT, 
) 
    BEGIN 
    DECLARE EXIT HANDLER FOR SQLEXCEPTION 
    BEGIN 
     ROLLBACK; 
    END; 
    START TRANSACTION; 

    INSERT INTO TableA (
     some_data, 
     counter 
    ) 
    VALUES (
     _some_data_a, 
     1 
    ) 
    ON DUPLICATE KEY UPDATE 
     counter   = counter + 1; 

    SELECT last_insert_id() 
     INTO @newId; 

LIST INSERT ???: 
    INSERT INTO TableB (
     table_a_id, some_data 
    ) VALUES (
     @newId, 
     list_item, 
    ); 
END LIST INSERT ??? 

    COMMIT; 
    END ;; 
DELIMITER ; 

我的想法是通过在通过逗号分隔字符串插入表B的项目列表中。这些值是字符串。我不确定在LIST INSERT部分要做什么。我需要某种循环吗?到目前为止,这个存储过程是否是正确的方法?我不想做一个批处理,因为我可能有数百甚至数千的项目在列表中。有更好的解决方案吗?我正在使用直接JDBC。

回答

2

是的,您需要一个循环,您可以在其中使用substring_index()获取列表中的值。解决方案是基于从this SO topic的答案:

DELIMITER ;; 
CREATE PROCEDURE insert_group_alert(
    IN _some_data_a   VARCHAR(255), 
    IN _data_list_b   TEXT, 
) 
    BEGIN 
    DECLARE strLen INT DEFAULT 0; 
    DECLARE SubStrLen INT DEFAULT 0; 
    DECLARE EXIT HANDLER FOR SQLEXCEPTION 
    BEGIN 
     ROLLBACK; 
    END; 
    START TRANSACTION; 

    INSERT INTO TableA (
     some_data, 
     counter 
    ) 
    VALUES (
     _some_data_a, 
     1 
    ) -- you do not really need this, since you do not provide an id 
    ON DUPLICATE KEY UPDATE 
     counter   = counter + 1; 

    SELECT last_insert_id() 
     INTO @newId; 

    do_this: 
     LOOP 
     SET strLen = LCHAR_ENGTH(_data_list_b); 

     INSERT INTO TableB (table_a_id, some_data) VALUES(@newId,SUBSTRING_INDEX(_data_list_b, ',', 1)); 

     SET SubStrLen = CHAR_LENGTH(SUBSTRING_INDEX(_data_list_b, ',', 1))+2; 
     SET _data_list_b = MID(_data_list_b, SubStrLen, strLen); --cut the 1st list item out 

     IF _data_list_b = '' THEN 
      LEAVE do_this; 
     END IF; 
     END LOOP do_this; 

    COMMIT; 
    END ;; 
DELIMITER ; 
+0

这就像一个冠军。 – Gremash