Below is the sample code of my Stored Procedure in which I am working on for interest calculation. This code is not executable because according to finding its getting issue whi
Some notes about what is possible with AUTO_INCREMENT
setup:
create table t1
( ai int not null auto_increment,
b int primary key
)ENGINE=InnoDB;
-- Error 1075: AI must be a key
create table t2
( ai int not null auto_increment,
b int primary key,
key(ai)
)ENGINE=InnoDB;
-- This is successful
create table t3
( ai int not null auto_increment,
b int primary key,
c int not null,
key(ai,c)
)ENGINE=InnoDB;
-- This is successful
create table t4
( ai int not null auto_increment,
b int primary key,
c int not null,
key(c,ai)
)ENGINE=InnoDB;
-- Error 1075: AI must be a key (ai is not left-most in composite)
create table t5
( ai int auto_increment primary key,
b int not null,
c int not null
)ENGINE=InnoDB;
-- Success: This is the PREDOMINANT way of doing it
create table t6
( ai int not null AUTO_INCREMENT,
b int not null,
c int not null,
PRIMARY KEY(c,ai)
)ENGINE=InnoDB;
-- Error 1075: AI must be a key (ai is not left-most in PK)
create table t7
( ai int not null AUTO_INCREMENT,
b int not null,
c int not null,
PRIMARY KEY(ai,c)
)ENGINE=InnoDB;
-- Success
create table t8
( ai int not null AUTO_INCREMENT,
b int not null,
c int not null,
KEY(ai),
KEY(c,ai)
)ENGINE=InnoDB;
insert t8(b,c) values(1,2);
insert t8(b,c) values(33,44);
select * from t8;
+----+----+----+
| ai | b | c |
+----+----+----+
| 1 | 1 | 2 |
| 2 | 33 | 44 |
+----+----+----+
Note ENGINE=MyISAM behaves differently, such as allowing the AI to be non-left most.
Stored Proc:
DROP PROCEDURE IF EXISTS `sp_interest_calculation_test`;
DELIMITER $$
CREATE PROCEDURE `sp_interest_calculation_test`(
IN sub_type CHAR(1)
)
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE l_ledger_id INT;
DECLARE dr_sum DECIMAL(14,2) DEFAULT 0;
DECLARE l_dr_amount, l_cr_amount, l_balance DECIMAL(14,2);
DECLARE cur_saving_acc CURSOR
FOR SELECT ledger_id, dr_amount, cr_amount, balance FROM tmp_interest order by id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
DROP TABLE IF EXISTS tmp_interest;
CREATE TEMPORARY TABLE IF NOT EXISTS tmp_interest(
id int(11) NOT NULL AUTO_INCREMENT,
ledger_id INT UNSIGNED,
dr_amount DECIMAL(14,2),
cr_amount DECIMAL(14,2),
balance DECIMAL(14,2),
KEY(id)
);
INSERT tmp_interest (ledger_id,dr_amount,cr_amount,balance) VALUES
(101,100,0,200),(102,140,0,340),(103,0,50,290);
OPEN cur_saving_acc;
read_loop: LOOP
FETCH cur_saving_acc INTO l_ledger_id, l_dr_amount, l_cr_amount, l_balance;
IF done THEN
LEAVE read_loop;
END IF;
SET dr_sum=dr_sum+l_dr_amount;
END LOOP;
CLOSE cur_saving_acc;
SELECT CONCAT('sum of debits=',dr_sum) as outCol;
END;$$
DELIMITER ;
Test:
call sp_interest_calculation_test('s');
+----------------------+
| outCol |
+----------------------+
| sum of debits=240.00 |
+----------------------+
The above CURSOR
setup is the proper way to do a FETCH
loop with a LEAVE
and a handler. Cursor loops are finicky. Don't directly mess with the done
variable. You are trusting the FETCH
and the handler with it. So let it deal with done
all on its own.
MySQL Manual Page on CURSORS. Also note that Cursors perform like junk. They are fun to play with. They can get you out of a tricky situation. But you bring performance to its knees when you use them.