I'm writing my first MySQL procedure. I try to generate a random number and update a value in a table with this number, but only if it doesn't exists already (due to unique constraint). My procedure looks like this:
create procedure generaterc()
begin
declare _rc char;
declare _id int;
set _id = 1;
while _id < ((select count(*) from patient) - 1) do
begin
set _rc = cast(FLOOR(1000000000 + (RAND() * 8999999999)) AS char);
select _rc;
if not exists(select * from patient where patient.rc = _rc) then
update patient set rc=_rc where id=_id;
set _id=_id+1;
end if;
end;
end while;
end
I got this error when executing the procedure: Data truncation: Data too long for column '_rc' at row 8. My rc column is varchar(255), but I guess this isn't the core of the problem. Any suggestions?
Thank you very much.
Instead of
declare _rc char;
try:
declare _rc varchar(255);
Currently _rc can only hold a single character, which is not enough to store your number.
However, for your use case you may like to take a look at the uuid_short() function. It generates a large random number that is guaranteed to be unique (subject to some rules). This way you can replace your procedure with the single statement:
update patient set rc = uuid_short();
Related
I am a beginner to MYSQL and currently practicing stored procedures. I am trying to create a procedure that should fetch a row of an entire field when given an input parameter. Is there any workaround for this? If yes, then it would be an immense help.
Many Thanks
Welcome to the Forum.
A stored procedure can simple consist of a SELECT statement that returns all the columns in the row you want. e.g.
CREATE PROCEDURE `myproc`(IN `p_id` INT(11))
READS SQL DATA
SELECT id, COL2, COL3, ETC
FROM `mytable`
WHERE id = 'p_id';
If you need to traverse a table, looking at every row that meets some criteria, then you need to DECLARE a "cursor", and use that to fetch the rows you want. Here is a template I use to create new procedures that need to traverse a table - it can be adapted to suit your needs. In this template I nly retrieve two columns from the cursor, but you can retrieve any number. You have to declare a local variable for each column in your SELECT so the FETCH statement has somewhere to put the data it retrieves from the cursor:
CREATE PROCEDURE `traverse_table`()
READS SQL DATA
BEGIN
DECLARE var_id INT(11) UNSIGNED;
DECLARE var_data varchar(16383);
DECLARE done INT DEFAULT FALSE;
DECLARE ecode varchar(1000) ;
DECLARE emsg varchar(1000) ;
DECLARE nextrecord CURSOR FOR # here is the CURSOR DECLARATION
SELECT `myid`,`mydata` # It will return these rows, one
FROM `mytable` # at a time
WHERE `mydata` LIKE "ABC%";
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1 ecode = RETURNED_SQLSTATE, emsg = MESSAGE_TEXT;
SELECT var_id,var_data,ecode,emsg;
END;
OPEN nextrecord;
FETCH nextrecord into var_id,var_data; # here is the first Fetch
WHILE (done = FALSE) DO
# >>>>>> do something with var_id,var_data here <<<<<<
SET done = FALSE;
FETCH NEXT FROM records into var_id,var_data; # here is the second and subsequent Fetch
END WHILE;
CLOSE nextrecord;
END
I intend to write a procedure to run a query on each of the tables in a provided list (can be a comma separated list or a table - undecided on that yet)
I started off with creating a while loop to iterate through each element in the provided list. Have been able to extract each element but I don't know how to run a query for that extracted element/table.
DELIMITER $$
DROP PROCEDURE IF EXISTS retain_demo_clients$$
CREATE PROCEDURE retain_demo_clients()
BEGIN
DECLARE counter INT(10);
DECLARE client_tables VARCHAR(255);
DECLARE table_count INT(10);
DECLARE table_in_process VARCHAR(255);
SET counter = 1;
SET table_count = 3;
SET client_tables = 'client_table, somerandomstuff, somemorestuff';
WHILE (counter < table_count +1) DO
SET table_in_process = substring_index(substring_index(client_tables, ',',counter),',',-1);
SELECT table_in_process;
SET counter = counter +1;
END WHILE;
END$$
DELIMITER ;
CALL retain_demo_clients();
I expect to do something like 'select * from table_in_process'. Would also appreciate if there is a better way to loop through the list of tables.
Here is DBFiddle link, if someone wants to tinker: https://www.db-fiddle.com/f/v6EMsiWvXFrBoNLgoZwDVX/1
You can use EXECUTE to run a text that represent a single statement
SET #someQuery = CONCAT('SELECT * FROM ', table_in_process ) ;
PREPARE preparable_stmt FROM #someQuery;
EXECUTE preparable_stmt;
used the following stored procedure to find reverse of a number , but it is showing error:use the right syntax to use near loop.
DELIMITER //
CREATE PROCEDURE ggrepeat1()
begin
declare num1 int;
declare num2 int;
declare rev int default 0;
set #num1:='&num1';
while num1>0
loop
set #num2:=num1 mod 10;
set #rev:=num2+(rev*10);
set #num1:=floor(num1/10);
end loop;
dbms_output.put_line('Reverse number is: '||rev);
end//
DELIMITER ;
As noted in the comments, you can't use oracle syntax in mysql. Regardless, I think you're over-complicating things. A simpler approach would be to cast your number to a string, reverse it using built-in functions and cast it back to a number:
CREATE FUNCTION reverse_int(num INT)
RETURNS INT DETERMINISTIC
RETURN CAST(REVERSE(CAST(num AS CHAT)) AS INT);
The while loop in mysql should be used in this like.
This is the first problem
while n>0 do
content..
end while
The second problem is
dbms_output.put_line('Reverse number is: '||rev);
In mysql you cannot use the above code.
Instead you can use this
Select 'The reverse of number is 'rev;
So your code would be
DELIMITER //
CREATE PROCEDURE ggrepeat1()
begin
declare num1 int;
declare num2 int;
declare rev int default 0;
set #num1:='&num1';
while num1>0 do
set #num2:=num1 mod 10;
set #rev:=num2+(rev*10);
set #num1:=floor(num1/10);
end while;
Select 'Reverse number is: 'rev;
end//
DELIMITER ;
Basically i'm going to run this procedure anytime a student enrolls/drops a course.
I'm trying to set student_total = # of students in a course, then update that corresponding section with (student_total + 1) i'm having trouble finding good documentation for stored procedures. I'm getting an error on my Declare student_total int; line. What am i not doing correct?
DELIMITER $$
CREATE PROCEDURE `mydb`.`update_seats` (IN section_ID varchar(20))
BEGIN
SET #section_id=section_id;
DECLARE student_total int;
-- count the number of students in the course --
SET student_total = SELECT count(student_ID) from course
WHERE section_ID = #section_id;
Update Section SET students_enrolled = (student_total + 1)
WHERE section_ID = #section_id;
END
Problems
Error 1
From MySql documentation:
DECLARE is permitted only inside a BEGIN ... END compound statement and must be at its start, before any other statements.
So, you should move DECLARE... statement before the SET #section_id... statement.
Error 2
You are trying to select a value into a variable using invalid snytax! You should use SELECT ... INTO instead of SET ... = SELECT ... (which is invalid syntax).
Removing Redundancy
No need to assign parameter (section_ID) to a global variable (#section_ID). You can simply change the parameter name to avoid name collision with section.section_ID column.
Solution
DELIMITER ;;
CREATE PROCEDURE `update_seats` (IN p_section_ID VARCHAR(20))
BEGIN
DECLARE student_total INT;
SELECT count(student_ID)
INTO student_total
FROM course
WHERE section_ID = p_section_ID;
UPDATE section
SET students_enrolled = (student_total + 1)
WHERE section_ID = p_section_ID;
END;;
DELIMITER ;
You're using the command line tool, yes?
It would be helpful to know the error message you received but based off the code you posted I don't see where you reset the delimiter command after the BEGIN...END block.
Taken from http://dev.mysql.com/doc/refman/5.1/en/stored-programs-defining.html
How do you declare variable and set a value which is a return from a query on them later.
Sample Stored Procedure:
DELIMITER $$
CREATE PROCEDURE `sampledb`.`SetVariableEx`()
BEGIN
-- declare variable
DECLARE xVarA INT;
DECLARE xVarB INT;
-- in this line, i would like to set a value on xVarA which is a COUNT
-- of record from table SINGLETABLE
-- i am getting error on this line.
SELECT xVarA := COUNT(*) FROM SingleTable;
-- the value of xVarA is added by 1 and set it to xVarB
SET xVarB = xVarA + 1;
-- insert the value of xVarB to the table SINGLETABLE
INSERT INTO SingleTable(SingleColumn) VALUES (xVarB);
-- lastly, display all records.
SELECT * FROM SingleTable;
END$$
DELIMITER ;
how would i do that?
Try the following:
SET xVarA := (SELECT COUNT(*) FROM SingleTable);
However, for this example, have you considered using an auto auto-incrementing value, rather than managing the value yourself?