MySQL store procedure Assign value to multiple variable from select statement - mysql

This is my Stored procedure . I have problem to assign value to Declared variable . When I Execute it, Insert and Update Command work fine but VALUE of Declared Variable remain 0; But I have some value in Database. How can i Do this Corectly.
BEGIN
DECLARE PaidFee INT DEFAULT 0;
DECLARE DueFee INT DEFAULT 0;
DECLARE CourseFee INT DEFAULT 0;
INSERT INTO `creditdirectory`(`TypeID`, `PersonName`, `CreditBy`, `PersonID`, `ModeOfPayment`,`Details`,`Amount`,`CompanyID`)
VALUES(1,PersonName,CreditBy, AddmissionID, ModeOfPayment, 'Installment', PaidAmount,
CompanyID);
SELECT `CourseFee`,`PaidFee`,`DueFee` INTO CourseFee,PaidFee,DueFee FROM `studentcoursedetails` WHERE `ID`= CourseID;
SET PaidFee = PaidFee + PaidAmount;
SET DueFee = CourseFee - PaidFee;
IF (NextDueDate !='') THEN
UPDATE `studentcoursedetails` SET `PaidFee` = PaidFee, `DueFee` = DueFee, `DueDate` = NextDueDate WHERE `ID`= CourseID;
ELSE
UPDATE `studentcoursedetails` SET `PaidFee` = PaidFee, `DueFee` = DueFee, `DueDate` = NULL WHERE `ID` = CourseID;
END IF;
END

Don't use variables with same name of columns, the query will take preference on table column names.
A good idea is use variables with prefix:
BEGIN
DECLARE p_PaidFee INT DEFAULT 0;
DECLARE p_DueFee INT DEFAULT 0;
DECLARE p_CourseFee INT DEFAULT 0;
INSERT INTO `creditdirectory`(`TypeID`, `PersonName`, `CreditBy`, `PersonID`, `ModeOfPayment`,`Details`,`Amount`,`CompanyID`)
VALUES(1,PersonName,CreditBy, AddmissionID, ModeOfPayment, 'Installment', PaidAmount,
CompanyID);
SELECT `CourseFee`,`PaidFee`,`DueFee` INTO p_CourseFee,p_PaidFee,p_DueFee FROM `studentcoursedetails` WHERE `ID`= CourseID;
SET p_PaidFee = p_PaidFee + PaidAmount;
SET p_DueFee = p_CourseFee - p_PaidFee;
IF (NextDueDate !='') THEN
UPDATE `studentcoursedetails` SET `PaidFee` = p_PaidFee, `DueFee` = p_DueFee, `DueDate` = NextDueDate WHERE `ID`= CourseID;
ELSE
UPDATE `studentcoursedetails` SET `PaidFee` = p_PaidFee, `DueFee` = p_DueFee, `DueDate` = NULL WHERE `ID` = CourseID;
END IF;
END

Related

How to write an update statement to update columns and check for prime numbers?

I am just learning to code SQL. Can someone help me with an update statement, I have done the insert but am stuck with an update. My table prime_test has two columns number and is_prime
Here is the question:
Write one or more update statements that sets the 'is_prime' column for each associated integer. For a prime, the column should read 'prime'. For non-primes, the column should read 'composite'.
My code
CREATE TABLE `sql_inventory`.`prime_test` (
`number` INT NOT NULL,
`is_prime` VARCHAR(50) NULL,
PRIMARY KEY (`number`));
INSERT INTO `prime`.`prime_test`
(`number`)
VALUES
(rand()*(100-2+1)+2);
Function to find the prime numbers:
CREATE FUNCTION isPrime(#num int)
RETURNS VARCHAR(50)
BEGIN
DECLARE #prime_or_notPrime INT
DECLARE #counter INT
DECLARE #retVal VARCHAR(50)
SET #retVal = 'composite'
SET #prime_or_notPrime = 1
SET #counter = 2
WHILE (#counter <= #number/2 )
BEGIN
IF (( #number % #counter) = 0 )
BEGIN
set #prime_or_notPrime = 0
BREAK
END
IF (#prime_or_notPrime = 1 )
BEGIN
SET #retVal = 'prime'
END
SET #counter = #counter + 1
END
return #retVal
END
update prime_test
set is_prime = dbo.isPrime(select number From 'prime'.'prime_test')

SQL Error: No data - zero rows fetched, selected, or processed

CREATE PROCEDURE KC_update_pricing()
BEGIN
DECLARE u_sku VARCHAR(10) DEFAULT "";
DECLARE u_product_size VARCHAR(4) DEFAULT "";
DECLARE u_product_name VARCHAR(100) DEFAULT "";
DECLARE u_chargeble_area DECIMAL DEFAULT 0.0;
DECLARE u_user_id VARCHAR(10) DEFAULT "";
DECLARE u_last_update DATE;
DECLARE cur1 CURSOR FOR
SELECT
sku,
product_size,
product_name,
chargeble_area,
user_id,
last_update
FROM kcproduct_test_load
WHERE last_update >= (SELECT DATE_FORMAT(DATE_SUB(max(last_update), INTERVAL 1 DAY), '%d-%m-%Y')
FROM kcpricing_test_load);
OPEN Cur1;
LOOP
FETCH cur1
INTO u_sku, u_product_size, u_product_name, u_chargeble_area, u_user_id, u_last_update;
IF (u_product_size = 'S')
THEN
SET u_shipping = 99;
ELSEIF (u_product_size = 'M')
THEN
SET u_shipping = 149;
ELSEIF (u_product_size = 'L')
THEN
SET u_shipping = 199;
ELSEIF (u_product_size = 'XS')
THEN
SET u_shipping = 99;
ELSEIF (u_product_size = 'XXS')
THEN
SET u_shipping = 69;
ELSE
SET u_shipping = 199;
END IF;
UPDATE kcpricing_test_load
SET base_price = (u_chargeble_area * 150)
WHERE sku = u_SKU;
END LOOP;
END;
have an exception command in the cursor some thing like below :
Exception
When NO_DATA_FOUND then
continue
end;
it will help to avoid no data found error.

Update row null fields with values from similar rows (same "key")

My question is kind of hard to explain in title so I'll show the data and goal.
There is a MySQL table with following structure:
CREATE TABLE customerProjectData(
idCustomer INT NOT NULL,
idProject INT DEFAULT NULL,
comePersons SMALLINT DEFAULT NULL,
comePairs SMALLINT DEFAULT NULL,
comment VARCHAR(255) DEFAULT NULL,
idCity INT DEFAULT NULL,
idStreet INT DEFAULT NULL,
name VARCHAR(64) DEFAULT NULL,
surname VARCHAR(64) DEFAULT NULL,
homeNum VARCHAR(10) DEFAULT NULL,
postCode CHAR(6) DEFAULT NULL,
postCity VARCHAR(64) DEFAULT NULL,
cellPhone VARCHAR(12) DEFAULT NULL
)
The thing is, there shold be also PRIMARY KEY(idCustomer, idProject) defined and it's not. As a result There are kind of duplicates (with the same primary key) but with different data.
I could run ALTER IGNORE TABLE but data loss would probably be unacceptable and unpredicatable. Finally we decided to try to fill null fields with values from duplicates if they contain data and after that run the ALTER IGNORE TABLE. Much less data will be lost that way and it's acceptable in this case (it's better than leaving it as it is now in longer time perspective).
The question is how to fill those fields from each duplicate.
Here is a rough try.
First try to find out the no. of rows which have the same key.
<?php
// $link is the database identifier
$sql = 'SELECT COUNT(*) AS num, * FROM `customerProjectData` GROUP BY `idCustomer`, `idProject` HAVING COUNT(*) > 1 ORDER BY COUNT(*) ASC;';
$run = mysql_query( $sql, $link );
$rows = array();
if( $run && mysql_num_rows( $run ) ) {
while( ( $fetch = mysql_fetch_assoc( $run ) ) !== false ) {
$rows[] = $fetch;
}
}
?>
Now $rows contains a list of all rows which have the same key and a count of how many times this key has been repeated in the table.
You can write a function which then iterates count times and see which rows has the complete data and use that to populates other records with this record's data.
A bit of trial and error.
I used #web-nomad suggestion and did something similar, but in sql procedure:
DROP PROCEDURE IF EXISTS correctCPD$$
CREATE PROCEDURE correctCPD()
BEGIN
DECLARE currentCustomerId INT;
DECLARE currentProjectId INT;
DECLARE cur_idCustomer INT;
DECLARE cur_idProject INT;
DECLARE cur_comePersons SMALLINT;
DECLARE cur_comePairs SMALLINT;
DECLARE cur_comment VARCHAR(255);
DECLARE cur_idCity INT;
DECLARE cur_idStreet INT;
DECLARE cur_name VARCHAR(64);
DECLARE cur_surname VARCHAR(64);
DECLARE cur_homeNum VARCHAR(10);
DECLARE cur_postCode CHAR(6);
DECLARE cur_postCity VARCHAR(64);
DECLARE cur_cellPhone VARCHAR(12);
CREATE TEMPORARY TABLE ids (
idCustomer INT,
idProject INT
) ENGINE = InnoDB;
INSERT INTO ids
SELECT idCustomer, idProject FROM customerprojectdata group by idCustomer, idProject having count(*) > 1;
BLOCK1: BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE itemCur CURSOR FOR SELECT idCustomer, idProject FROM ids;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN itemCur;
itemCurLoop: LOOP
FETCH itemCur INTO currentCustomerId, currentProjectId;
IF done THEN
LEAVE itemCurLoop;
END IF;
BLOCK2: BEGIN
DECLARE doneIn INT DEFAULT FALSE;
DECLARE cpdCur CURSOR FOR SELECT idCustomer, idProject, comePersons, comePairs, comment, idCity, idStreet, name, surname, homeNum, postCode, postCity, cellPhone FROM customerProjectData WHERE idCustomer = currentCustomerId AND idProject = currentProjectId;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET doneIn = TRUE;
OPEN cpdCur;
cpdCurLoop: LOOP
FETCH cpdCur INTO
cur_idCustomer, cur_idProject, cur_comePersons, cur_comePairs,
cur_comment, cur_idCity, cur_idStreet, cur_name, cur_surname,
cur_homeNum, cur_postCode, cur_postCity, cur_cellPhone;
IF doneIn THEN
LEAVE cpdCurLoop;
END IF;
UPDATE CustomerProjectData SET
comePersons = IF((comePersons IS NULL OR comePersons = '') AND cur_comePersons > 0, cur_comePersons, comePersons),
comePairs = IF((comePairs IS NULL OR comePairs = '') AND cur_comePairs > 0, cur_comePairs, comePairs),
comment = IF((comment IS NULL OR comment = '') AND cur_comment > 0, cur_comment, comment),
idCity = IF((idCity IS NULL AND idStreet IS NULL) AND cur_idCity > 0, cur_idCity, idCity),
idStreet = IF(((idCity IS NULL OR idCity = cur_idCity) AND idStreet IS NULL) AND cur_idStreet > 0, cur_idStreet, idStreet),
name = IF((name IS NULL OR name = '') AND cur_name > 0, cur_name, name),
surname = IF((surname IS NULL OR surname = '') AND cur_surname > 0, cur_surname, surname),
homeNum = IF((homeNum IS NULL OR homeNum = '') AND cur_homeNum > 0, cur_homeNum, homeNum),
postCode = IF((postCode IS NULL OR postCode = '') AND cur_postCode > 0, cur_postCode, postCode),
postCity = IF((postCity IS NULL OR postCity = '') AND cur_postCity > 0, cur_postCity, postCity),
cellPhone = IF((cellPhone IS NULL OR cellPhone = '') AND cur_cellPhone > 0, cur_cellPhone, cellPhone)
WHERE idCustomer = currentCustomerId AND idProject = currentProjectId;
END LOOP;
CLOSE cpdCur;
END BLOCK2;
END LOOP;
CLOSE itemCur;
END BLOCK1;
DROP TEMPORARY TABLE ids;
END$$
Thanks for help!

Looping through multiple loops in

DROP PROCEDURE fillBin;
DELIMITER $$
CREATE PROCEDURE fillBin(IN a INT(11), IN b INT(11), IN c INT(11), IN d INT(11), IN e INT(11))
wholeblock:BEGIN
DECLARE i INT UNSIGNED DEFAULT 1;
DECLARE j INT UNSIGNED DEFAULT 1;
DECLARE k INT UNSIGNED DEFAULT 1;
DECLARE l INT UNSIGNED DEFAULT 1;
DECLARE m INT UNSIGNED DEFAULT 1;
DECLARE strA VARCHAR(255) DEFAULT '';
DECLARE strB VARCHAR(255) DEFAULT '';
DECLARE strC VARCHAR(255) DEFAULT '';
DECLARE strD VARCHAR(255) DEFAULT '';
DECLARE strE VARCHAR(255) DEFAULT '';
DECLARE strF VARCHAR(255) DEFAULT '';
SET strA = 'A';
SET strB = 'G';
SET strC = 'R';
SET strD = 'S';
SET strE = 'B';
SET strF= '';
WHILE i < (a+1) DO
SET strA=CONCAT(strA,i) ;
WHILE j < (b+1) DO
SET strB = CONCAT(strB,j);
WHILE k < (c+1) DO
SET strC =CONCAT(strC,k);
WHILE l < (d+1) DO
SET strD = CONCAT(strD,l);
WHILE m < (e+1) DO
SET strE = CONCAT(strE,m);
SET strF = CONCAT(strA, strB, strC, strD, strE);
INSERT INTO BIN (`aisle`, `room`, `rack`, `shelf`, `bin`, `barcode`, `warehouse_id`)
VALUES(strA,strB, strC, strD, strE, strF, 1);
SET m=m+1;
SET strE = 'B';
END WHILE;
SET l=l+1;
SET strD = 'S';
END WHILE;
SET k=k+1;
SET strC = 'R';
END WHILE;
SET j=j+1;
SET strB = 'G';
END WHILE;
SET i=i+1;
SET strA = 'A';
END WHILE;
END $$
//calling the procedure
CALL fillBin(1, 1, 1, 2, 2);
My procedure inserts the values: A1G1R1S1B1 and A1G1R1S1B2. And the inner loop breaks.
but the correct insertion should be: A1G1R1S1B1 and A1G1R1S1B2 and A1G1R1S2B1 and A1G1R1S2B2.
The insert is obviously incomplete. How should I place my insert statement or change the looping as to cater the needs?
Please help. Thanks
Why don't use simple SQL to do this task ?
Look at the following example
We need a table with a seqence of numbers from 1 to X - where X is a maximum number whenever we need.
CREATE TABLE numbers(
x int primary key auto_increment
);
INSERT INTO numbers
SELECT null FROM information_schema.columns;
SELECT max( x ) FROM numbers;
| MAX( X ) |
|----------|
| 558 |
And now the below simple select will generate all required records for us
(see this demo: http://sqlfiddle.com/#!2/1e5c4b/7
- you will need to scroll to the bottom of the page to see a result of the query):
SET #strA = 'A';
SET #strB = 'G';
SET #strC = 'R';
SET #strD = 'S';
SET #strE = 'B';
SET #strF= '';
SET #a = 2;
SET #b = 2;
SET #c = 2;
SET #d = 2;
SET #e = 2;
SELECT *,
CONCAT(strA, strB, strC, strD, strE) strF,
1 As warehouse_id
FROM (
SELECT Concat(#strA,x) strA
FROM numbers
WHERE x <= #a
) A
CROSS JOIN
(
SELECT Concat(#strB,x) strB
FROM numbers
WHERE x <= #b
) B
CROSS JOIN
(
SELECT Concat(#strC,x) strC
FROM numbers
WHERE x <= #c
) C
CROSS JOIN
(
SELECT Concat(#strD,x) strD
FROM numbers
WHERE x <= #d
) D
CROSS JOIN
(
SELECT Concat(#strE,x) strE
FROM numbers
WHERE x <= #e
) E
And now just place an INSERT statement at the top of the above query:
INSERT INTO BIN (`aisle`, `room`, `rack`, `shelf`, `bin`, `barcode`, `warehouse_id`)
SELECT *,
CONCAT(strA, strB, strC, strD, strE) strF,
1 As warehouse_id
FROM (
SELECT Concat(#strA,x) strA
FROM numbers
WHERE x <= #a
) A
CROSS JOIN
(
SELECT Co .....
........
........
........

Mysql cursor fetches only first row

Mysql cursor fetches only first row and when it has fetched the second row the row_not_found variable is set to false and cursor close.
Please look into below SP:
CREATE DEFINER = 'root'#'localhost'
PROCEDURE billingv2test.SP_CreateRecurringBillingOrders(IN _billingDate DATETIME,
IN _defaultBillingFrequency INT,
IN _IsForcedExecution BIT)
BEGIN
DECLARE _userId char(36);
DECLARE _billingStartDate datetime;
DECLARE _billingEndDate datetime;
DECLARE _cmd VARCHAR(4000);
DECLARE _userBillingHistoryId char(36);
DECLARE _paymentOrderId char(36);
DECLARE _orderNumber VARCHAR(100);
DECLARE _totalChargeAmount DECIMAL(15, 6);
DECLARE _couponChargeAmount DECIMAL(15, 6);
DECLARE _pendingChargeAmount DECIMAL(15, 6);
DECLARE _isError BIT;
DECLARE _noOfUsersProcessed BIT;
DECLARE _billingResourceType VARCHAR(20);
DECLARE _RowNo INT;
DECLARE _defaultDateTime DATETIME;
DECLARE record_not_found INTEGER DEFAULT 0;
DECLARE user_list varchar(200);
DECLARE ProcessUsersForRecurringBilling_Cursor CURSOR FOR
SELECT OwnerId FROM UserBillingInfo
WHERE NextBillingDate IS NOT NULL
AND cast(NextBillingDate as date) <= cast( _billingDate as date)
AND IsProcessPending = 0
AND IsDeleted = 0
AND BillingStatus <> 'Delinquent'
ORDER BY NextBillingDate;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET record_not_found = 1;
SET _isError = 0;
SET _noOfUsersProcessed = 0;
SET _defaultDateTime = '1900-01-01 00:00:00';
SET _userBillingHistoryId = UUID();
INSERT INTO BillingHistory( Id, BillingStartTime, BillingEndTime, Status, NoOfUsersProcessed, CreateTime, UpdateTime )
VALUES ( _userBillingHistoryId, UTC_TIMESTAMP(), NULL , 'Started', 0, UTC_TIMESTAMP(), UTC_TIMESTAMP());
OPEN ProcessUsersForRecurringBilling_Cursor;
allusers: LOOP
FETCH ProcessUsersForRecurringBilling_Cursor INTO _userId;
IF record_not_found THEN
LEAVE allusers;
END IF;
SET user_list = CONCAT(IFNULL(user_list,''),", ",_userId);
SET _isError = 0;
SET _orderNumber = '';
SET _totalChargeAmount = '0';
SET _couponChargeAmount = '0';
SET _pendingChargeAmount = '0';
UPDATE UserBillingInfo SET IsProcessPending = 1 WHERE OwnerId = _userId;
SET _billingStartDate = _defaultDateTime;
SELECT
IFNULL(InvoiceDate, _defaultDateTime) INTO _billingStartDate
FROM
PaymentOrder
WHERE OwnerId = _userId AND OrderStatus IN ('Success', 'Submitted')
ORDER BY CreateTime DESC
LIMIT 1;
SELECT NextBillingDate INTO _billingEndDate FROM UserBillingInfo WHERE OwnerId = _userId;
SET _orderNumber = UUID();
SET _orderNumber = SUBSTRING(_orderNumber, 0, LOCATE('-', _orderNumber));
-- CALL SP_CreateRecurringBillingPaymentOrder
CALL SP_CreateRecurringBillingPaymentOrder
(_userId, _billingStartDate, _billingEndDate, _orderNumber, _userBillingHistoryId, _paymentOrderId);
SELECT Amount INTO _totalChargeAmount FROM PaymentOrder WHERE Id = _paymentOrderId;
SET _pendingChargeAmount = _totalChargeAmount;
UPDATE PaymentOrder set ChargeAmount = _pendingChargeAmount, UpdateTime = UTC_TIMESTAMP()
WHERE Id = _paymentOrderId;
UPDATE ResourceUsageProcessed SET BillingStatus = 'Completed'
WHERE PaymentOrderId = _paymentOrderId AND BillingStatus = 'Processing';
SET _noOfUsersProcessed = _noOfUsersProcessed + 1;
END LOOP allusers;
CLOSE ProcessUsersForRecurringBilling_Cursor;
UPDATE BillingHistory SET NoOfUsersProcessed = _noOfUsersProcessed, Status = 'Completed', BillingEndTime = UTC_TIMESTAMP()
WHERE Id = _userBillingHistoryId;
END
hey this may sound silly but try this
IF record_not_found=1 THEN
LEAVE allusers;