MySQL insert multiple rows with function with while loop - mysql

I'm trying to insert multiple rows in a MySQL database. First, I create insert function for address, which connects to another table that only contains the formatted address, so I make inserts for it in another function.
Then in a third function I'm trying to populate a third table with first generating dummy addresses for it. For some reason even the first lower level function (address_insert()) fails to execute due to SQL syntax error and I cannot figure out what it could be. Any ideas?
Thanks!
First function:
DROP PROCEDURE IF EXISTS address_insert;
CREATE PROCEDURE address_insert()
BEGIN
DECLARE i INT DEFAULT (SELECT COUNT(*) FROM hoop.address) + 1;
DECLARE counter INT DEFAULT 0;
WHILE (counter < 5) DO
INSERT INTO hoop.address (adr_id, address, city, country, created_at, lat, lng, updated_at, zip)
VALUES (i, CONCAT("Address-", i), "City", "United States", CURRENT_TIMESTAMP, RAND(35, 50), RAND(80, 120), CURRENT_TIMESTAMP, "ZIPCODE");
SET i = i + 1;
SET counter = counter + 1;
END WHILE;
END;
Second function:
DROP PROCEDURE IF EXISTS address_shop_insert;
CREATE PROCEDURE address_shop_insert()
BEGIN
DECLARE i INT DEFAULT (SELECT COUNT(*) FROM hoop.address_shop) + 1;
DECLARE counter INT DEFAULT 0;
WHILE (counter <= SELECT COUNT(*) FROM hoop.address) DO
INSERT INTO hoop.address_shop_insert (formatted_address, adr_id)
VALUES ("Formatted Address", i);
SET i = i + 1;
SET counter = counter + 1;
END WHILE;
END;
Final function:
DROP PROCEDURE IF EXISTS merchant_shop_insert;
CREATE PROCEDURE merchant_shop_insert()
BEGIN
address_insert()
address_shop_insert()
DECLARE i INT DEFAULT (SELECT COUNT(*) FROM hoop.merchant_shop) + 1;
DECLARE merchant_accounts INT DEFAULT (SELECT COUNT(*) FROM hoop.merchant_account) + 1;
DECLARE shop_address_id DEFAULT (SELECT COUNT(*) FROM hoop.address_shop) - 5;
DECLARE counter INT DEFAULT 1;
DECLARE account_mod INT DEFAULT 0;
DECLARE account_id INT DEFAULT 1;
WHILE (i < merchant_accounts) DO
IF
SELECT MOD(account_mod, 5) = 0
SET account_id = account_id + 1;
END IF;
IF counter = 5
SET shop_address_id = shop_address_id + 1;
SET counter = 1;
END IF;
INSERT INTO hoop.merchant_shop (shop_id, contact_name, contact_phone, created_at, shop_name, status, updated_at, acc_id, shop_adr_id)
VALUES (i, "Strawberry Peach", "+361/789-6544", CURRENT_TIMESTAMP, CONCAT("Shop", i), 1, CURRENT_TIMESTAMP, account_id, shop_address_id)
SET i = i + 1;
SET account_mod = account_mod + 1;
SET counter = counter + 1;
END WHILE;
END;

Since the semi-column ; ends a command, you need to define a specific one for the stored procedure creation, otherwise, MySQL won't know what is the delimiter that tells the end of the declaration of the procedure.
DROP PROCEDURE IF EXISTS address_insert;
-- Set the delimiter to $$
DELIMITER $$
-- Notice that every instructions IN the procedure will be ended by the regular delimiter ;
CREATE PROCEDURE address_insert()
BEGIN
DECLARE i INT DEFAULT (SELECT COUNT(*) FROM hoop.address) + 1;
DECLARE counter INT DEFAULT 0;
WHILE (counter < 5) DO
INSERT INTO hoop.address (adr_id, address, city, country, created_at, lat, lng, updated_at, zip)
VALUES (i, CONCAT("Address-", i), "City", "United States", CURRENT_TIMESTAMP, RAND(35, 50), RAND(80, 120), CURRENT_TIMESTAMP, "ZIPCODE");
SET i = i + 1;
SET counter = counter + 1;
END WHILE;
-- vv------------------------ Notice this
END$$
-- Set it back to ;
DELIMITER ;

Related

how to apply while loop for loop query in mysql

CREATE DEFINER=`root`#`localhost` PROCEDURE `test4`()
BEGIN
declare GroupArray text;
DECLARE i INT DEFAULT 0;
DECLARE loopcount INT DEFAULT 0;
declare GroupId varchar (5);
set GroupArray=(select group_concat(distinct groupId) from EventList_View);
SET loopcount = (SELECT LENGTH(GroupArray) -
LENGTH(REPLACE(GroupArray,',', '')));
select loopcount;
WHILE i <= loopcount DO
SET i = i + 1;
SET GroupId = (SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(GroupArray,
',', i),',', -1));
select GroupId;
END WHILE;
END
this is my query i am trying to apply while loop and i want get all groupId but GroupArray [1,2,3]i am getting value but in loop count i am getting 0 can any one please tell me where am doing wrong . why i am unable to get loop count null and why i am not getting value 1,2,3 for group

Cursor in mysql stored procedure executes only 1 iteration

I have been struck in this stored procedure for 2 days now.
Here's the code
BEGIN
DECLARE in_township_id INT DEFAULT 2;
DECLARE in_billing_month INT DEFAULT 1;
DECLARE in_billing_month_string VARCHAR(15) DEFAULT 'January';
DECLARE in_billing_year INT DEFAULT 2016;
DECLARE in_account_id INT DEFAULT 1;
DECLARE out_status INT DEFAULT 0;
DECLARE in_invoice_date DATETIME DEFAULT CURRENT_DATE();
DECLARE _no_flats INT;
DECLARE _current_month_data_exists INT;
DECLARE _flat_id INT;
DECLARE _current_billing_month, _current_billing_year INT;
DECLARE _next_billing_month, _next_billing_year INT;
DECLARE _current_balance, _new_balance FLOAT DEFAULT 0;
DECLARE _maintenance, _power_backup, _service_tax, _penalty FLOAT DEFAULT 0;
DECLARE _maintenance_price, _power_backup_price, _service_tax_price, _balance_price, _penalty_price FLOAT DEFAULT 0;
DECLARE _consumed_units INT;
DECLARE _penal_interest_remark, _maintenance_bill_remark, _power_backup_remark, _service_tax_remark, _maintenance_account_remark VARCHAR(100);
DECLARE _total_penalty, _total_maintenance, _total_power_backup, _total_service_tax FLOAT DEFAULT 0;
DECLARE _all_flats_cursor CURSOR FOR SELECT id FROM flat_resident_v WHERE township_id=2;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET _no_flats=1;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
SET out_status=2;
SELECT 'An error has occurred, operation rollbacked and the stored procedure was terminated';
END;
START TRANSACTION;
SET _current_billing_month=in_billing_month;
SET _current_billing_year=in_billing_year;
SET _next_billing_month=in_billing_month;
SET _next_billing_year=in_billing_year;
IF in_billing_month=1 THEN
SET _current_billing_month=12;
SET _current_billing_year=in_billing_year-1;
END IF;
IF in_billing_month=12 THEN
SET _next_billing_month=1;
SET _next_billing_year=in_billing_year+1;
ELSE
SET _next_billing_month = in_billing_month+1;
END IF;
SELECT CONCAT('On account of billing month ', in_billing_month_string) INTO _maintenance_account_remark;
SELECT penalty, rate_maintenance, rate_power_backup, service_tax_rate
INTO _penalty, _maintenance, _power_backup, _service_tax FROM account_master WHERE id=in_account_id;
SELECT CONCAT('Charged # ', _penalty*1200, '%') INTO _penal_interest_remark;
SELECT CONCAT('Charged # Rs. ', _maintenance, '/sq. feet') INTO _maintenance_bill_remark;
SELECT CONCAT('Charged # Rs. ', _power_backup, '/unit') INTO _power_backup_remark;
SELECT CONCAT('Charged # ', _service_tax_price*100, '%') INTO _service_tax_remark;
SET out_status = 0;
INSERT INTO temp(value1, value2) VALUES('SUCCESS', 'Initialization Completed');
OPEN _all_flats_cursor;
SET _no_flats=0;
ALL_FLATS_LOOP: LOOP
FETCH _all_flats_cursor INTO _flat_id;
IF _no_flats=1 THEN
INSERT INTO temp(value1, value2) VALUES('LOOP BREAK', _no_flats);
LEAVE ALL_FLATS_LOOP;
END IF;
IF _no_flats=0 THEN
INSERT INTO temp(value1, value2) VALUES('INSIDE LOOP', _no_flats);
INSERT INTO temp(value1, value2) VALUES('FLAT_ID', _flat_id);
SELECT count(FLATS.id) INTO _current_month_data_exists FROM account_flat_ledger as FLATS
WHERE FLATS.flat_id=_flat_id AND FLATS.debit_month=in_billing_month
AND FLATS.debit_year=in_billing_year FOR UPDATE;
IF _current_month_data_exists=0 THEN
SET out_status = 1;
INSERT INTO temp(value1, value2) VALUES('_current_month_data_exists', 'FAILED: Data not exists for billing year');
LEAVE ALL_FLATS_LOOP;
END IF;
SELECT consumed_units INTO _consumed_units FROM account_power_backup_usage
WHERE flat_id=_flat_id AND month=in_billing_month AND year=in_billing_year;
INSERT INTO temp(value1, value2) VALUES('SUCCESS', 'Power Ok');
SELECT balance INTO _current_balance FROM account_flat_ledger as FLATS
WHERE FLATS.flat_id=_flat_id AND FLATS.debit_month=_current_billing_month AND FLATS.debit_year=_current_billing_year FOR UPDATE;
IF _current_balance>0 THEN
SET _penalty_price = _penalty*_current_balance;
END IF;
SET _maintenance_price = _maintenance*1000;
SET _power_backup_price = _power_backup*_consumed_units;
SET _service_tax_price = _service_tax * (_maintenance+_power_backup);
SET _new_balance = _current_balance + _penalty + _maintenance + _power_backup + _service_tax;
INSERT INTO temp(value1, value2) VALUES('SUCCESS', 'All Values Set');
UPDATE account_flat_ledger SET penal_interest=_penalty_price, maintenance_bill=_maintenance_price, service_tax=_service_tax_price,
power_backup=_power_backup_price, opening_balance=_current_balance,received_amount=0, balance=_new_balance,
debit_date=CURDATE(), penal_interest_remark=_penal_interest_remark, maintenance_bill_remark=_maintenance_bill_remark,
power_backup_remark=_power_backup_remark, service_tax_remark=_service_tax_remark
WHERE flat_id=_flat_id AND debit_month=in_billing_month AND debit_year=in_billing_year;
INSERT INTO account_flat_ledger(flat_id, debit_month, debit_year)
VALUES(_flat_id, _next_billing_month, _next_billing_year);
INSERT INTO temp(value1, value2) VALUES('SUCCESS', 'Insertion of new Flats OK');
SET _total_maintenance = _total_maintenance + (_maintenance_price
+ _power_backup_price + _service_tax_price + _penalty_price);
SET _total_penalty = _total_penalty + _penalty_price;
SET _total_power_backup = _total_power_backup + _power_backup_price;
SET _total_service_tax = _total_service_tax + _service_tax_price;
INSERT INTO temp(value1, value2) VALUES('SUCCESS', 'Flat over');
END IF;
END LOOP ;
CLOSE _all_flats_cursor;
IF out_status != 0 THEN
ROLLBACK;
END IF;
SELECT #out_status;
END IF;
COMMIT;
END
Previously I have done this whole thing using Java code (using ResultSets and PreparedStatements). But someone told me to use stored procedure for this purpose to make things handy and efficient.
Problem: The loop i.e. Cursor executes only ones, but there are 3 records present in the table.
I used logging into temp table to trace the error but couldn't find.

MySQL If Statement and Increment

I am having issues with a MySQL If statement that creates a group rank. here is the MySQL Statement:
SELECT EnCode, EnName, QuScore,
#scorerank := IF(#currathlete = EnCode, #scorerank + 1, 1),
#currathlete := EnCode
FROM ranking ORDER BY EnCode, QuScore DESC
It currently gives the following output
'1004277','Ashe','1628','1','1004277'
'1004277','Ashe','1309','1','1004277'
'1004277','Ashe','1263','1','1004277'
'1004277','Ashe','648','1','1004277'
'1004277','Ashe','645','1','1004277'
'1004277','Ashe','1628','1','1004277'
'1015934', 'Sabina', '544', '1', '1015934'
'1015934', 'Sabina', '455', '1', '1015934'
'1015934', 'Sabina', '276', '1', '1015934'
'1015934', 'Sabina', '216', '1', '1015934'
What it should be doing is incrementing each of the '1' numbers by one for each row that has the same code, and then starting from 1 again when it sees a different code number (1004277, then 1015934 in this case)
Any help is appreciated as i have followed a number of examples online using the above method but seem to hit the same issue a this point.
Try this way in stored Procedure:
drop PROCEDURE if EXISTS INCREMENTME;
create PROCEDURE INCREMENTME()
BEGIN
DECLARE OldEnNamevar VARCHAR(10) DEFAULT NULL;
DECLARE done INT DEFAULT FALSE;
DECLARE Encodevar VARCHAR(10);
DECLARE EnNamevar VARCHAR(10);
DECLARE QuScorevar VARCHAR(10);
DECLARE scorerankvar VARCHAR(10);
DECLARE currathalthletevar VARCHAR(10);
DECLARE countcode int(29) DEFAULT(1);
DECLARE counter int(20) default 0;
DECLARE get_cur CURSOR FOR select `Encode`,`EnName`,`QuScore`,`scorerank`,`currathalthlete` from tbl_ranking;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;
drop table if exists temp_temptable;
create TEMPORARY table temp_temptable(Encodevar VARCHAR(50) NULL,EnNamevar VARCHAR(50) NULL,QuScorevar VARCHAR(50) NULL,scorerankvar VARCHAR(50) NULL,currathalthletevar VARCHAR(50) NULL,recordCount int(10) null);
OPEN get_cur;
REPEAT
set counter = counter + 1;
FETCH get_cur INTO Encodevar,EnNamevar,QuScorevar,scorerankvar,currathalthletevar;
if (OldEnNamevar = EnNamevar) THEN
set countcode = countcode +1;
ELSE
if(counter=1) then
set countcode = 1;
ELSE
set countcode = 0;
end if;
end if;
if (OldEnNamevar != EnNamevar) THEN
set countcode = 1;
end if;
if(OldEnNamevar=NULL) then
set countcode = 1;
end if;
insert into temp_temptable (Encodevar,EnNamevar,QuScorevar,scorerankvar,currathalthletevar,recordCount) values(Encodevar,EnNamevar,QuScorevar,scorerankvar,currathalthletevar,countcode);
set OldEnNamevar = EnNamevar;
UNTIL done END REPEAT;
select * from temp_temptable;
drop temporary table if exists temp_temptable;
CLOSE get_cur;
END
call the procedure like this:
call INCREMENTME();
Here's the result:
You have to initialize your variables, otherwise they are null (at least at the beginning of the session, probably not anymore if you run it twice), and your query will give strange results. Try
SELECT EnCode, EnName, QuScore,
#scorerank := IF(#currathlete = EnCode, #scorerank + 1, 1),
#currathlete := EnCode
FROM ranking, (select #currathlete := '', #scorerank := 0) init
ORDER BY EnCode, QuScore DESC

mysql trigger function

I have a table call lp_upload and it contain plate number of car and other related information:
CREATE TABLE `lp_upload` (
`date` date NULL ,
`plate` char(10) NULL ,
`site` int NULL ,
`dateid` char(20) NULL
)
;
this table is getting information from a traffic camera. however, sometime letter in the plate is not recognized and it will be replace by $. So if a plate is really abc123, but the camera didnt recognized c and 1, it will be ac$$23 that get enter into the table.
im suppose to make it so when a new plate is entered and 6 of its letters match an existing plate, it will become that plate. EX: 123$5678 is entered and 12345678 already exist, then 123$5678 will be replace by 12345678.
so i first wrote a match function:
CREATE DEFINER = CURRENT_USER FUNCTION `matchingfun`(`str1` char(10),`str2` char(10))
RETURNS int
BEGIN
DECLARE myindex int DEFAULT 0;
DECLARE count int DEFAULT 0;
DECLARE maxlength int;
SET maxlength = length(str1);
for_loop: LOOP
SET myindex = myindex + 1;
IF maxlength < myindex then
RETURN 0;
END IF;
IF SUBSTRING(str1,myindex,1)= SUBSTRING(str2,myindex,1)then
SET count = count +1;
END IF;
IF count > 6 then
RETURN 1;
END IF;
IF SUBSTRING(str1,myindex,1)!= SUBSTRING(str2,myindex,1) and SUBSTRING(str1,myindex,1)!= '$' and SUBSTRING(str2,myindex,1)!= '$'then
RETRUN 0;
END IF;
END LOOP for_loop;
RETURN 0;
END
and I added a trigger function to the table
CREATE TRIGGER `trigger1` AFTER INSERT ON `lpr_opt_upload`
BEGIN
declare old_site_id int;
declare old_text char(10);
select lpr_text into old_text from lpr_opt_upload where matchingfun(new.lpr_text, lpr_text) = 1;
if(old_text is not null) then
set new.lpr_text = old_text;
end if;
END
when i run this, the database crashes. can you help fix this problem or suggest a better way to do this. thanks.
I suspect that the problem you're running into is multiple matches. For example, if you have abcd01234 and abcde1234 in the database and attempt to insert abcd$1234, you'll get an error.
Now, I'm going to assume that this application is supposed to match OCR'd license plates from speed cameras or red-light cameras in order to facilitate ticketing of the vehicle owner. If that's the case, then you want to err on the side of caution and not have the system automatically try to pick from multiple candidates and instead have a real human look at the result and confirm the plate number.
So, operating on that assumption:
DELIMITER //
CREATE TRIGGER `attempt_match_existing_plate`
BEFORE INSERT
ON `lp_upload`
FOR EACH ROW BEGIN
DECLARE exist_plate CHAR(10);
DECLARE rowcount INT;
SELECT COUNT(*), plate INTO rowcount, exist_plate FROM lp_upload WHERE platematch(NEW.plate, plate) = 1;
IF (1 = rowcount) AND (exist_plate IS NOT NULL) THEN
SET NEW.plate = exist_plate;
END IF;
END
//
DELIMITER ;
DELIMITER //
CREATE DEFINER = CURRENT_USER
FUNCTION `platematch`(`plate_new` char(10), `plate_exist` char(10))
RETURNS INT
BEGIN
DECLARE myindex INT DEFAULT 0;
DECLARE match_count INT DEFAULT 0;
DECLARE maxlength INT;
SET maxlength = length(plate_new);
for_loop: LOOP
SET myindex = myindex + 1;
IF maxlength < myindex THEN
RETURN 0;
END IF;
IF SUBSTRING(plate_new, myindex, 1) = SUBSTRING(plate_exist, myindex, 1)
THEN
SET match_count = match_count +1;
END IF;
IF match_count >= 6 THEN
RETURN 1;
END IF;
IF SUBSTRING(plate_new, myindex, 1) != SUBSTRING(plate_exist, myindex, 1)
AND SUBSTRING(plate_new, myindex, 1) != '$'
AND SUBSTRING(plate_exist, myindex, 1) != '$'
THEN
RETURN 0;
END IF;
END LOOP for_loop;
RETURN 0;
END
//
DELIMITER ;
In the scenario I described above, abcd$1234 will be inserted into the database as-is instead of just being matched to one of multiple potential results automatically.

MySQL DELIMITER not working

I've tried a tutorial from this site, where a sample table gets inserted along with some testing data in a stored procedure. But unfortunately an error message is thrown, saying there's something wrong with the DELIMITER. The whole script is:
CREATE TABLE filler (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT
) ENGINE=Memory;
CREATE TABLE t_hierarchy (
id INT NOT NULL PRIMARY KEY,
parent INT NOT NULL,
lft INT NOT NULL,
rgt INT NOT NULL,
sets LineString NOT NULL,
data VARCHAR(100) NOT NULL,
stuffing VARCHAR(100) NOT NULL
) ENGINE=MyISAM;
DELIMITER $$
CREATE PROCEDURE prc_filler(cnt INT)
BEGIN
DECLARE _cnt INT;
SET _cnt = 1;
WHILE _cnt <= cnt DO
INSERT
INTO filler
SELECT _cnt;
SET _cnt = _cnt + 1;
END WHILE;
END;
CREATE PROCEDURE prc_hierarchy(width INT)
main:BEGIN
DECLARE last INT;
DECLARE level INT;
SET last = 0;
SET level = 0;
WHILE width >= 1 DO
INSERT
INTO t_hierarchy
SELECT COALESCE(h.id, 0) * 5 + f.id,
COALESCE(h.id, 0),
COALESCE(h.lft, 0) + 1 + (f.id - 1) * width,
COALESCE(h.lft, 0) + f.id * width,
LineString(
Point(-1, COALESCE(h.lft, 0) + 1 + (f.id - 1) * width),
Point(1, COALESCE(h.lft, 0) + f.id * width)
),
CONCAT('Value ', COALESCE(h.id, 0) * 5 + f.id),
RPAD('', 100, '*')
FROM filler f
LEFT JOIN
t_hierarchy h
ON h.id >= last;
SET width = width / 5;
SET last = last + POWER(5, level);
SET level = level + 1;
END WHILE;
END
$$
DELIMITER ;
START TRANSACTION;
CALL prc_filler(5);
CALL prc_hierarchy(585937);
COMMIT;
CREATE INDEX ix_hierarchy_parent ON t_hierarchy (parent);
CREATE INDEX ix_hierarchy_lft ON t_hierarchy (lft);
CREATE INDEX ix_hierarchy_rgt ON t_hierarchy (rgt);
CREATE SPATIAL INDEX sx_hierarchy_sets ON t_hierarchy (sets);
Executing this on a MySQL 5.0.51a-24+lenny2 server gives me the following error message:
[Err] 1310 - End-label $$ without match
Does anyone know why this occurs and how to fix it?
$$ should be after every created procedure.
CREATE PROCEDURE prc_filler(cnt INT)
BEGIN
DECLARE _cnt INT;
SET _cnt = 1;
WHILE _cnt <= cnt DO
INSERT
INTO filler
SELECT _cnt;
SET _cnt = _cnt + 1;
END WHILE;
END$$ -- here's your problem
That's why it is called delimiter - it separates SQL commands. You have ';' inside procedures and '$$' outside of them.
I have seen some MySQL clients that don't support the DELIMITER keyword and throw an error... I believe it is your case... You should try to use a different client, maybe the CLI tool bundled with MySQL (if you can...)?