将 Oracle SQL 过程转换为 MySQL 存储过程

Converting Oracle SQL Procedure into MySQL Stored Procedure

我正在尝试将复杂的 Oracle sql 过程转换为 mysql。该过程包含许多不同的选择、游标等。我已经在 mysql 中编写了它的一个版本,但它不起作用并且只给出一些错误消息。希望能帮到我。

表格

CREATE TABLE IF NOT EXISTS `NutritionalInformation` 
(
  `idNuIn` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
  `calories` FLOAT NULL,
  `saturatedFat` FLOAT NULL,
  `transFat` FLOAT NULL,
  `carbohydrates` FLOAT NULL,
  `sugar` FLOAT NULL,
  `protein` FLOAT NULL,
  `salt` FLOAT NULL
);

CREATE TABLE IF NOT EXISTS `Inventory` 
(
  `idInventory` INT NOT NULL,
  `idIngredient` INT NOT NULL,
  `idStore` INT NOT NULL,
  `expiryDate` DATE NULL,
  `deliveryDate` DATE NOT NULL,
  `amount` INT NOT NULL,
  `isAccessible` INT NOT NULL,  
  CONSTRAINT `fk_Inventory_Ingredient`
    FOREIGN KEY (`idIngredient`)
    REFERENCES `Ingredient` (`idIngredient`),
  CONSTRAINT `fk_Inventory_StoreA`
    FOREIGN KEY (`idStore`)
    REFERENCES `WaffleStore` (`idStore`),
  CONSTRAINT pk_Inventory
    PRIMARY KEY (idInventory)
);

CREATE TABLE IF NOT EXISTS `Inventory` 
(
  `idInventory` INT NOT NULL,
  `idIngredient` INT NOT NULL,
  `idStore` INT NOT NULL,
  `expiryDate` DATE NULL,
  `deliveryDate` DATE NOT NULL,
  `amount` INT NOT NULL,
  `isAccessible` INT NOT NULL,  
  PRIMARY KEY (`idIngredient`, `idStore`),
  CONSTRAINT `fk_Inventory_Ingredient`
    FOREIGN KEY (`idIngredient`)
    REFERENCES `Ingredient` (`idIngredient`),
  CONSTRAINT `fk_Inventory_StoreA`
    FOREIGN KEY (`idStore`)
    REFERENCES `WaffleStore` (`idStore`)
);

CREATE TABLE IF NOT EXISTS `Product` 
(
  `idProduct` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
  `idNuIn` INT NOT NULL,
  `price` FLOAT NOT NULL,
  `name` VARCHAR(255) NOT NULL,
  CONSTRAINT `fk_Product_NutritionalInformation1`
    FOREIGN KEY (`idNuIn`)
    REFERENCES `NutritionalInformation` (`idNuIn`)
);

CREATE TABLE IF NOT EXISTS `Waffle` 
(
  `idWaffle` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
  `creatorName` VARCHAR(255) NULL,
  `creationDate` DATE NOT NULL,
  `processingTimeSec` INT,
  `healty` VARCHAR(255),
  CONSTRAINT `fk_Waffle_Product1`
    FOREIGN KEY (`idWaffle`)
    REFERENCES `Product` (`idProduct`)
);

CREATE TABLE IF NOT EXISTS `WaffleIngredient` 
(
  `idIngredient` INT NOT NULL,
  `idWaffle` INT NOT NULL,
  `amount` INT NOT NULL,
  PRIMARY KEY (`idIngredient`, `idWaffle`),
  CONSTRAINT `fk_WaffleRecept_Ingredient1`
    FOREIGN KEY (`idIngredient`)
    REFERENCES `Ingredient` (`idIngredient`),
  CONSTRAINT `fk_WaffleRecept_Waffle1`
    FOREIGN KEY (`idWaffle`)
    REFERENCES `Waffle` (`idWaffle`)
);

CREATE TABLE IF NOT EXISTS `WaffleStore` 
(
  `idStore` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
  `name` VARCHAR(255) NULL,
  `areaCode` VARCHAR(15) NULL,
  `location` VARCHAR(255) NULL,
  `streetName` VARCHAR(255) NULL,
  `houseNumber` VARCHAR(45) NULL
);

插入示例

INSERT INTO NutritionalInformation (idNuIn, calories, saturatedFat, transFat, carbohydrates, sugar, protein, salt)
    VALUES (4, 60, 0, 0, 0, 0, 0, 0);
    
INSERT INTO NutritionalInformation (idNuIn, calories, saturatedFat, transFat, carbohydrates, sugar, protein, salt)
    VALUES (5, 350, 3, 3, 5, 5, 3, 1);
    
INSERT INTO INGREDIENT (idIngredient, idNuIn, name, unit, price, processingTimeSec)
    VALUES (3, 4, 'Apfel', 'g', 0.5, 3); 
    
INSERT INTO PRODUCT (idProduct, idNuIn, price, name)
    VALUES (4, 5, 3.5, 'ApfelWaffel');
    
INSERT INTO WAFFLE (idWaffle, creatorName, creationDate, processingTimeSec, healty)
    VALUES (4, 'Berndt', '2020-12-01', NULL, NULL);
    
INSERT INTO WAFFLEINGREDIENT(idIngredient, idWaffle, amount)
    VALUES (3, 4, 2); 

INSERT INTO WaffleStore (idStore, name, areaCode, location, streetName, houseNumber)
    VALUES (1, 'Waffle GMBH', '50000', 'TEST', 'TEST', '38');
    
INSERT INTO INVENTORY(idInventory, idIngredient, idStore, expiryDate, deliveryDate, amount, isAccessible)
    VALUES (2, 3, 1, '3032-12-30', '3032-12-30', 100, 1); 
    
INSERT INTO WaffleOrder(idOrder, idStore, totalAmount, paymentStatus, orderDate)
    VALUES (1, 1, 2, 0, '2020-12-30');

Oracle SQL 过程

CREATE OR REPLACE PROCEDURE OnInventoryAdd (
    s_idProduct IN INT,
    s_idOrder IN INT,
    s_extenal_amount IN INT
)
IS
    v_store INT;
    v_waffle_id INT;
    
    v_cursor_ingredientid INT;
    v_cursor_amount INT;
    
    v_cursor_expiryDate DATE;
    v_cursor_deliveryDate DATE;
    
    v_operator VARCHAR(3) := 'add';
    
    CURSOR v_Ingredient_Cursor_On_Insert(w_Id INT) IS
        SELECT idIngredient, amount FROM WAFFLEINGREDIENT WHERE idWaffle = w_Id;
        
    CURSOR v_Ingredient_Cursor_On_Delete(i_id INT) IS
        SELECT expiryDate, deliveryDate FROM Inventory WHERE idIngredient = i_id;
BEGIN
    SELECT idStore INTO v_store FROM WAFFLEORDER WHERE idOrder = s_idOrder;
    SELECT w.idWaffle INTO v_waffle_id FROM Waffle w WHERE w.idProduct = s_idProduct;
    
    -- If more than one waffle is bought
    FOR x IN 1..s_extenal_amount LOOP
        -- Get all ingredient information of waffle
        OPEN v_Ingredient_Cursor_On_Insert(v_waffle_id);
        LOOP
             FETCH v_Ingredient_Cursor_On_Insert INTO v_cursor_ingredientId, v_cursor_amount;
             EXIT WHEN v_Ingredient_Cursor_On_Insert%NOTFOUND;
             
             -- Get all old expirydate and deliverydate information
             OPEN v_Ingredient_Cursor_On_Delete(v_cursor_ingredientId);
             LOOP
                 FETCH v_Ingredient_Cursor_On_Delete INTO v_cursor_expiryDate, v_cursor_deliveryDate;
                 EXIT WHEN v_Ingredient_Cursor_On_Delete%NOTFOUND;
             END LOOP;
             CLOSE v_Ingredient_Cursor_On_Delete;
        END LOOP;
        CLOSE v_Ingredient_Cursor_On_Insert;
        
    -- Update the Inventory
    InventoryUpdate(v_store, v_cursor_ingredientId, v_cursor_amount, v_operator, v_cursor_expiryDate, v_cursor_deliveryDate);
    END LOOP;
END;
/

当前版本

DROP PROCEDURE IF EXISTS `OnInventoryAdd`;
DELIMITER //

CREATE PROCEDURE `OnInventoryAdd` (
    s_idProduct INT,
    s_idOrder INT,
    s_extenal_amount INT
)
BEGIN 
    DECLARE loop_counter INT DEFAULT s_extenal_amount;
    
    DECLARE v_store INT;
    DECLARE v_waffle_id INT;
    
    DECLARE v_cursor_ingredientid INT;
    DECLARE v_cursor_amount INT;
    
    DECLARE v_cursor_expiryDate DATE;
    DECLARE v_cursor_deliveryDate DATE;
    
    DECLARE v_operator VARCHAR(3) DEFAULT 'add';
    
    DECLARE v_c_insert_done, v_c_delete_done BOOLEAN DEFAULT FALSE;
    
    DECLARE v_Ingredient_Cursor_On_Insert CURSOR FOR
        SELECT idIngredient, amount FROM WAFFLEINGREDIENT WHERE idWaffle = v_waffle_id;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_c_insert_done = TRUE;
     
    SELECT idStore INTO v_store FROM WAFFLEORDER WHERE idOrder = s_idOrder;
    SELECT idWaffle INTO v_waffle_id FROM Waffle WHERE idWaffle = s_idProduct;
    
    WHILE loop_counter > 0 DO
        SET loop_counter = loop_counter - 1;
        
        OPEN v_Ingredient_Cursor_On_Insert;
        curr_insert_loop: LOOP
            FETCH FROM v_Ingredient_Cursor_On_Insert INTO v_cursor_ingredientId, v_cursor_amount;
            
            IF v_c_insert_done THEN 
                CLOSE v_Ingredient_Cursor_On_Insert;
                LEAVE curr_insert_loop; 
            END IF;
            
            BLOCK2 : BEGIN
                DECLARE v_Ingredient_Cursor_On_Delete CURSOR FOR
                    SELECT expiryDate, deliveryDate FROM Inventory WHERE idIngredient = v_cursor_ingredientid;
                DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_c_delete_done = TRUE;
                
                OPEN v_Ingredient_Cursor_On_Delete;
                curr_delete_loop : LOOP
                    FETCH FROM v_Ingredient_Cursor_On_Delete INTO v_cursor_expiryDate, v_cursor_deliveryDate;
                    
                    IF v_c_delete_done THEN
                        CLOSE v_Ingredient_Cursor_On_Delete;
                        LEAVE curr_delete_loop;
                    END IF;
                END LOOP curr_delete_loop;
            END BLOCK2;
        END LOOP curr_insert_loop;
        CALL InventoryUpdate(v_store, v_cursor_ingredientId, v_cursor_amount, v_operator, v_cursor_expiryDate, v_cursor_deliveryDate);
    END WHILE;
    
END //

DELIMITER ;

错误

4 row(s) affected, 2 warning(s): 1264 Out of range value for column 'expiryDateOnInsert' at row 2 1264 Out of range value for column 'deliveryDateOnInsert' at row 1

即使我编写了 Oracle 过程,我对如何在 MYSQL 中编写相同的行为以及如何修复此错误一无所知。如果有没有游标的替代方法也可以这样做

好的,我已经成功地将 oracle 过程转换为 mysql 存储过程,这是工作代码:

代码

CREATE PROCEDURE `OnInventoryAdd` (
    s_idProduct INT,
    s_idOrder INT,
    s_extenal_amount INT
)
BEGIN 
    DECLARE loop_counter INT DEFAULT s_extenal_amount;
    DECLARE done1, done2 BOOLEAN DEFAULT FALSE;
    
    DECLARE v_store INT;
    DECLARE v_waffle_id INT;
    
    DECLARE v_operator VARCHAR(3) DEFAULT 'add';
    
    DECLARE v_cursor_ingredientid INT;
    DECLARE v_cursor_amount INT;
    
    DECLARE v_cursor_expiryDate DATE;
    DECLARE v_cursor_deliveryDate DATE;
    
    DECLARE v_Ingredient_Cursor_On_Insert CURSOR FOR
        SELECT idIngredient, amount FROM WAFFLEINGREDIENT WHERE idWaffle = v_waffle_id;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done1 = TRUE;
    
    SELECT idStore INTO v_store FROM WAFFLEORDER WHERE idOrder = s_idOrder;
    SELECT idWaffle INTO v_waffle_id FROM Waffle WHERE idWaffle = s_idProduct;

    REPEAT
       OPEN v_Ingredient_Cursor_On_Insert;
       loop1 : LOOP
          FETCH FROM v_Ingredient_Cursor_On_Insert INTO v_cursor_ingredientId, v_cursor_amount;
          
          IF done1 THEN
             CLOSE v_Ingredient_Cursor_On_Insert;
             LEAVE loop1;
          END IF;
          
          BLOCK1 : BEGIN
          
            DECLARE v_Ingredient_Cursor_On_Delete CURSOR FOR
                    SELECT expiryDate, deliveryDate FROM Inventory WHERE idIngredient = v_cursor_ingredientid;
            DECLARE CONTINUE HANDLER FOR NOT FOUND SET done2 = TRUE;
            
            OPEN v_Ingredient_Cursor_On_Delete;
            loop2 : LOOP
               FETCH FROM v_Ingredient_Cursor_On_Delete INTO v_cursor_expiryDate, v_cursor_deliveryDate;
               
               IF done2 THEN
                  SET done2 = FALSE; -- This was the solution
                  LEAVE loop2;
               END IF;
               
            END LOOP loop2;
         END BLOCK1;
       END LOOP loop1;
       CALL InventoryUpdate(v_store, v_cursor_ingredientId, v_cursor_amount, v_operator, v_cursor_expiryDate, v_cursor_deliveryDate);
       SET loop_counter = loop_counter - 1;
    UNTIL loop_counter = 0
    END REPEAT;

END //

DELIMITER ;