2016-02-03 72 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