【问题标题】:How to insert multiple rows based on a quantity value in one row?如何根据一行中的数量值插入多行?
【发布时间】:2012-02-07 09:46:45
【问题描述】:

在 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 中而不是代码中执行此操作,以将所有转换步骤保持在一起(还有很多其他步骤)。

【问题讨论】:

    标签: mysql loops insert


    【解决方案1】:

    JYelton 针对他/她自己的问题的解决方案中的错字:

    获取 item_cur INTO parent_id_val, item_type_val, quantity_val;

    应该是:

    获取 item_cur INTO parent_id_val, quantity_val, item_type_val;

    其他都很好。

    【讨论】:

      【解决方案2】:

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

      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】:

        根据其他提供了一些见解的答案,我能够找到其他信息 (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 和其他地方经常阅读和遇到它们,这是一个学习的好机会

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

        【讨论】:

          【解决方案4】:

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

          看来你必须做类似的任务。您可以从下面的示例中了解如何在存储过程中使用数据库游标来遍历 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% 相同。只做必要的改变。它会起作用的。

          【讨论】:

          • 感谢您的示例,这有助于找到解决方案。
          【解决方案5】:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-01-30
            • 1970-01-01
            • 2012-12-21
            • 1970-01-01
            • 2023-03-17
            • 1970-01-01
            • 2016-06-13
            • 2023-03-09
            相关资源
            最近更新 更多