For each supplier(name) show the names of the items it supplies.
Files.sql
I happen to have the following data in my database
Database creation and deletion
DROP DATABASE IF EXISTS almacen;
CREATE DATABASE IF NOT EXISTS almacen;
Create and Add data to the table articulos
USE almacen;
CREATE TABLE articulos(
cod_art VARCHAR(6) PRIMARY KEY,
descripcion VARCHAR(45),
precio FLOAT,
stock INT,
caducidad BOOLEAN,
cod_prov VARCHAR(4),
observaciones VARCHAR(45)
);
INSERT INTO articulos VALUES('DR-001','Lejia',0.80,18,FALSE,'A002','Muy Toxica'),
('DR-002','Suavizante',2.40,10,FALSE,'A001','No volcar'),
('DR-003','Quitamancha',5.00,18,FALSE,'B001','Muy Toxico'),
('PA-001','Pan',1.00,35,TRUE,'B001','No tocar con las manos'),
('PA-002','Palmerita',2.10,8,TRUE,'A001','Aplicar max 5 paquetes'),
('PA-003','Napolitana',1.00,44,TRUE,'A002','Chocolate crema'),
('VE-001','Lechuga',1.50,27,TRUE,'B002','No meter en la nevera'),
('VE-002','Zanahoria',3.00,330,TRUE,'A001','No meter en la nevera');
Create and Add data to the clientes table
CREATE TABLE clientes(
cod_cliente INT AUTO_INCREMENT PRIMARY KEY,
dni VARCHAR(9),
nombreCli VARCHAR(25),
ap1 VARCHAR(35),
ap2 VARCHAR(35),
descuento INT
);
INSERT INTO clientes VALUES(null,'45098765G','Juan','Perez','Soler',5),
(null,'33456739H','Antonio','Garcia','Toro',8),
(null,'23478962S','Ramon','Gonzalez','Tamudo',0),
(null,'45765432F','Jesus','Duarte','Fortes',4),
(null,'29876098G','Gabriel','Lopez','Vazquez',2);
Create and Add data to the detallesFacturas
CREATE TABLE detallesFacturas(
nFactura INT,
cod_art VARCHAR(6),
cantidad INT,
desc_especial INT,
PRIMARY KEY (nFactura,cod_art)
);
INSERT INTO detallesFacturas VALUES(6,'DR-003',5,2),
(6,'PA-002',2,6),
(7,'DR-003',4,0),
(7,'DR-002',2,2),
(8,'VE-002',3,5),
(8,'PA-001',7,5),
(1,'DR-001',2,2),
(1,'PA-002',5,0),
(1,'DR-002',10,4),
(1,'VE-001',3,0),
(2,'DR-002',2,4),
(2,'VE-002',3,5),
(2,'PA-001',2,2),
(3,'PA-002',4,4),
(3,'VE-002',1,3),
(3,'DR-001',3,2),
(4,'PA-001',2,0),
(4,'PA-002',3,5),
(4,'VE-002',2,2),
(5,'VE-001',4,6),
(5,'PA-001',3,3);
Create and Add data to the facturas
CREATE TABLE facturas(
nFactura INT AUTO_INCREMENT PRIMARY KEY,
nCliente INT,
fecha DATE,
forma_pago VARCHAR(20)
);
INSERT INTO facturas VALUES(null,3,'2007-10-10','Contado'),
(null,2,'2007-10-11','Contado'),
(null,5,'2007-10-11','Cheque'),
(null,1,'2007-10-12','Transferencia'),
(null,5,'2007-10-14','Contado'),
(null,1,'2007-10-16','Cheque'),
(null,2,'2007-10-16','Transferencia'),
(null,4,'2007-10-17','Contado');
Create and Add data to the proveedores
CREATE TABLE proveedores(
cod_prov VARCHAR(4) PRIMARY KEY,
nombre_prov VARCHAR(30),
telefono VARCHAR(9),
ciudad VARCHAR(20),
descuento_1 INT,
descuento_2 INT
);
INSERT INTO proveedores VALUES('A001','Distribuciones Sur','956525354','Ceuta',5,10),
('A002','Todomasa SL','952875309','Malaga',3,6),
('A003','La mancha pastelera','953709912','Jaen',15,20),
('B001','Romelsa','912345762','Madrid',10,20),
('B002','Gegatur SL','933988344','Barcelona',7,13);
Cursor.sql
USE almacen;
DELIMITER $$
DROP PROCEDURE IF EXISTS art $$
CREATE PROCEDURE art()
BEGIN
DECLARE fin boolean;
DECLARE c1_codProv VARCHAR(4);
DECLARE c1_nomProv VARCHAR(30);
DECLARE c2_Articulos VARCHAR(20);
DECLARE cur_proveedor CURSOR FOR SELECT cod_prov,nombre_prov FROM proveedores;
DECLARE cur_articulos CURSOR FOR SELECT descripcion FROM articulos WHERE cod_prov=c1_codProv;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET fin=true;
SET fin=0;
OPEN cur_proveedor;
FETCH cur_proveedor INTO c1_codProv,c1_nomProv;
WHILE fin=false DO
SELECT c1_nomProv;
FETCH cur_proveedor INTO c1_codProv,c1_nomProv;
OPEN cur_articulos;
FETCH cur_articulos INTO c2_Articulos;
WHILE fin=false DO
SELECT c2_Articulos;
FETCH cur_articulos INTO c2_Articulos;
END WHILE;
SET fin = false;
CLOSE cur_Articulos;
FETCH cur_proveedor INTO c1_codProv,c1_nomProv;
END WHILE;
CLOSE cur_proveedor;
END $$
DELIMITER ;
call art();
And my cursor fails me because it does not return the expected result. For example DISTRIBUCIONES SUR should give me SUAVIZANTE, PALMERITA and ZANAHORIA.
RUN EXAMPLE
I found my bug. It turns out that I had a fetch left over and that's why it cut me off and didn't give it to me correctly because it overwrote what I had before.
The fetch that was left over is the one that is commented on
USE almacen;
DELIMITER $$
DROP PROCEDURE IF EXISTS art $$
CREATE PROCEDURE art()
BEGIN
DECLARE fin boolean DEFAULT FALSE;
DECLARE c1_codProv VARCHAR(4);
DECLARE c1_nomProv VARCHAR(30);
DECLARE c2_Articulos VARCHAR(20);
DECLARE cur_proveedor CURSOR FOR SELECT cod_prov,nombre_prov FROM proveedores;
DECLARE cur_articulos CURSOR FOR SELECT descripcion FROM articulos WHERE cod_prov=c1_codProv;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET fin=true;
OPEN cur_proveedor;
FETCH cur_proveedor INTO c1_codProv,c1_nomProv;
WHILE fin=FALSE DO
SELECT c1_nomProv;
# FETCH cur_proveedor INTO c1_codProv,c1_nomProv;
OPEN cur_articulos;
FETCH cur_articulos INTO c2_Articulos;
WHILE fin=FALSE DO
SELECT c2_Articulos;
FETCH cur_articulos INTO c2_Articulos;
END WHILE;
SET fin = FALSE;
CLOSE cur_Articulos;
FETCH cur_proveedor INTO c1_codProv,c1_nomProv;
END WHILE;
SET fin = FALSE;
CLOSE cur_proveedor;
END $$
DELIMITER ;
call art();
RUN EXAMPLE :
I am trying to convert a complex oracle sql procedure to mysql. The procedure contains of many differenct selects, cursors etc. I already wrote a version of it in mysql, but it does not work and only gives some error messages. I hope on could help me.
Tables
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
);
Example Inserts
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 PROCEDURE
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;
/
Current Version
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 ;
Error
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
Even tho I wrote the Oracle Procedure, I have zero clue how to write the same behavior in MYSQL and more over how to fix this error. If there is a alternative to do the same without cursors, then it would be fine too
Ok, I've managed to convert the oracle procedure into mysql stored procedure, here is the working code:
Code
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 ;