如何根据一行中的数量值插入多行?

时间:2012-01-11 00:15:00

标签: mysql loops insert

在MySQL中,我将每个项目类型(一定数量的项目)的单行转换为每个项目的单行,以便可以存储有关各个项目的其他详细信息。

以下是一个示例源表:

id    parent_id    qty    item_type
--    ---------    ---    ---------
1     10291        2      widget
2     10292        4      thinger

我想创建一个新表,其中包含一个新列,其中包含无法应用于多个项目的信息。因此,上表最终将如下:

id    parent_id    item_type    info
--    ---------    ---------    ----
1     10291        widget       [NULL]
2     10291        widget       [NULL]
3     10292        thinger      [NULL]
4     10292        thinger      [NULL]
5     10292        thinger      [NULL]
6     10292        thinger      [NULL]

有没有办法可以迭代或循环源表的每一行,插入一些等于源qty列的记录?我更喜欢在sql而不是代码中执行此操作以将所有转换步骤保持在一起(还有许多其他步骤)。

5 个答案:

答案 0 :(得分:2)

您可以使用存储过程。那将是如下。下面是我用于根据数量将产品插入日志的存储过程。

似乎你必须做类似的任务。您可以从下面的示例中了解如何在存储过程中使用数据库游标来循环MySQL中的结果集。

   DELIMITER $$
     DROP PROCEDURE IF EXISTS CursorProc$$
     CREATE PROCEDURE CursorProc()
     BEGIN
     DECLARE  no_more_products, quantity_in_stock INT DEFAULT 0;
     DECLARE  prd_code VARCHAR(255);
                 DECLARE  cur_product CURSOR FOR 
     SELECT  productCode FROM products;
       DECLARE  CONTINUE HANDLER FOR NOT FOUND 
     SET  no_more_products = 1;

     /* for  loggging information */
     CREATE  TABLE infologs (
     Id int(11) NOT NULL AUTO_INCREMENT,
     Msg varchar(255) NOT NULL,
     PRIMARY KEY (Id)
     );
     OPEN  cur_product;

     FETCH  cur_product INTO prd_code;
     REPEAT 
     SELECT  quantityInStock INTO quantity_in_stock
     FROM  products
     WHERE  productCode = prd_code;

     IF  quantity_in_stock < 100 THEN
     INSERT  INTO infologs(msg)
     VALUES  (prd_code);
     END  IF;
     FETCH  cur_product INTO prd_code;
     UNTIL  no_more_products = 1
     END REPEAT;
     CLOSE  cur_product;
     SELECT *  FROM infologs;
     DROP TABLE  infologs;
     END$$
     DELIMITER;

似乎您的任务与上述程序的90%相同。做一些必要的改变。它会起作用。

答案 1 :(得分:1)

我认为您可以创建存储过程,声明一个读取源表的游标,并为每一行插入qty行到目标表中。

答案 2 :(得分:1)

这只是我在这里的代码示例,它不适合您的需求,但它完全符合您的需要,而且它比过程或临时表简单。

SELECT event, id, order_ref, storeitem_barcode_create(8), NOW()
FROM (
    SELECT mss.id, mss.event, mss.order_ref, mss.quantity, mss.product_id, 
    @rowID := IF(@lastProductID = mss.product_id AND @lastID = mss.id, @rowID + 1, 0) AS rowID, 
    @lastProductID := mss.product_id, 
    @lastID := mss.id
FROM module_barcode_generator mbg, 
(SELECT @rowID := 0, @lastProductID := 0, @lastID := 0) t
INNER JOIN module_events_store_sold mss ON mss.order_ref = "L18T2P"
) tbl
WHERE rowId < quantity;

答案 3 :(得分:0)

根据提供一些见解的其他答案,我能够找到其他信息(by Kevin Bedell)来创建存储过程并在循环中使用游标。我简化了我的解决方案,以便它与我的问题中的示例匹配:

DROP PROCEDURE IF EXISTS proc_item_import;
DELIMITER $$
CREATE PROCEDURE proc_item_import()
BEGIN
    # Declare variables to read records from the cursor
    DECLARE parent_id_val INT(10) UNSIGNED;
    DECLARE item_type_val INT(10) UNSIGNED;
    DECLARE quantity_val INT(3);

    # Declare variables for cursor and loop control
    DECLARE no_more_rows BOOLEAN;
    DECLARE item_qty INT DEFAULT 0;

    # Declare the cursor
    DECLARE item_cur CURSOR FOR
        SELECT
            i.parent_id, i.qty, i.item_type
        FROM items i;

    # Declare handlers for exceptions
    DECLARE CONTINUE HANDLER FOR NOT FOUND
    SET no_more_rows = TRUE;

    # Open the cursor and loop through results
    OPEN item_cur;

    input_loop: LOOP

        FETCH item_cur
        INTO parent_id_val, item_type_val, quantity_val;

        # Break out of the loop if there were no records or all have been processed
        IF no_more_rows THEN
            CLOSE item_cur;
            LEAVE input_loop;
        END IF;

        SET item_qty = 0;

        qty_loop: LOOP

            INSERT INTO items_new
                (parent_id, item_type)
            SELECT
                parent_id_val, item_type_val;

            SET item_qty = item_qty + 1;

            IF item_qty >= quantity_val THEN
                LEAVE qty_loop;
            END IF;

        END LOOP qty_loop;

    END LOOP input_loop;
END$$
DELIMITER ;

在提出这个问题之前,我没有使用存储过程,游标或循环。也就是说,我已经在SE和其他地方经常阅读并遇到过这些,这是学习的好机会

值得注意的是,凯文页面上面的示例(上面链接的)不使用END%%(只是END),这在尝试让脚本工作时引起了一些麻烦。在创建过程时,有必要临时更改分隔符,以便分号终止过程内的语句,而不是过程本身的创建过程。

答案 4 :(得分:0)

Typo在JYelton的解决方案中提出了他/她自己的问题:

FETCH item_cur         INTO parent_id_val,item_type_val,quantity_val;

应该是:

FETCH item_cur         INTO parent_id_val,quantity_val,item_type_val;

否则非常好。