Как вставить несколько строк на основе количественного значения в одной строке? - PullRequest
1 голос
/ 11 января 2012

В 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 ]

2 голосов
/ 11 января 2012

Вы можете сделать с помощью хранимой процедуры. Это будет как ниже. Ниже представлена ​​хранимая процедура, которую я использую для вставки продуктов в журнал в зависимости от их количества.

Кажется, вы должны сделать подобное задание. Вы можете узнать, как использовать курсор базы данных в хранимой процедуре для циклического перебора результирующего набора в 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 голос
/ 15 августа 2012

Это просто пример кода, который у меня есть, он не адаптирован к вашим потребностям, но он делает именно то, что вам нужно, и это проще, чем процедура или временная таблица.

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;
1 голос
/ 11 января 2012

Я думаю, вы можете создать хранимую процедуру, объявить курсор, который читает исходную таблицу и для каждой строки вставляет qty строк в целевую таблицу.

0 голосов
/ 01 июля 2017

Опечатка в решении Джелтона для его / ее собственного вопроса:

FETCH item_cur INTO parent_id_val, item_type_val, amount_val;

Должно быть:

FETCH item_cur INTO parent_id_val, Quantity_val, item_type_val;

В остальном очень хорошо.

0 голосов
/ 12 января 2012

Основываясь на других ответах, которые дали некоторое представление, я смог найти дополнительную информацию ( Кевина Беделла ), чтобы создать хранимую процедуру и использовать курсор в цикле.Я упростил свое решение, чтобы оно соответствовало примеру в моем вопросе:

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), что вызвало головную боль при попытке заставить скрипт работать.При создании процедуры необходимо временно изменить разделитель, чтобы точки с запятой завершали операторы внутри процедуры, но не процесс создания самой процедуры.

...