在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而不是代码中执行此操作以将所有转换步骤保持在一起(还有许多其他步骤)。
答案 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;
否则非常好。