Convert SQL Server Cursor To MySQL - mysql

How to convert a SQL Server cursor to MySQL?
ALTER function [dbo].[Terlambat](#proses int) returns #tempKK table (krk int,terlambat int) as
begin
declare #uid int, #total_hari_kerja int
select #total_hari_kerja = SUM(alokasi) from proses
declare krk_uid cursor for select distinct krk from kartu_kendali where proses <= 8
open krk_uid
fetch next from krk_uid into #uid
while (##FETCH_STATUS = 0)
begin
insert into #tempKK select top 1 krk, dbo.GetTerlambat(realisasi_tgl_terima, #total_hari_kerja) terlambat from kartu_kendali where proses = 1 and krk = #uid order by RecID
fetch next from krk_uid into #uid
end
close krk_uid
deallocate krk_uid
return
end

For changing a cursor to MySQL that has no cursor you should follow this solution:
Add a Row Number to your SELECT statement that help you to fetch data from your SELECT over it.
Now, you can use a variable that starts with 1 and grows inside the WHILE in each step by 1 and filter your SELECT statement over Row Number and this variable.

Related

Differentiate between no results returned and end of rows for cursor

I'm trying to implement a cursor in MYSQL. Inside that cursor, I have a select statement that might or might not return any rows.
I'm facing a problem when that query does not return any rows.
According to the MYSQL documentation,
NOT FOUND: Shorthand for the class of SQLSTATE values that begin with '02'. This is relevant within the context of cursors and is used to control what happens when a cursor reaches the end of a data set. If no more rows are available, a No Data condition occurs with SQLSTATE value '02000'. You can set up a handler for it or a NOT-FOUND condition to detect this condition. For another example, see Section 13.6.6, “Cursors”. The NOT FOUND condition also occurs for SELECT ... INTO var_list statements that retrieve no rows.
My termination of the cursor is implemented as usual.
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET FINISHED = 1;
The problem is that the termination is triggered because of the query inside the cursor returning 0 rows. Is there a way to differentiate between those two cases so that the cursor continues despite my query returning 0 results?
Thanks in advance.
DROP PROCEDURE IF EXISTS CURSOR_PLACEHOLDER;
DELIMITER $$
CREATE PROCEDURE CURSOR_PLACEHOLDER()
BEGIN
DECLARE FINISHED INTEGER DEFAULT 0;
DECLARE CURRENT_ROW_ID VARCHAR(256);
DEClARE CURRENT_ROW
CURSOR FOR
SELECT ID
FROM A
WHERE ID_P IN (SELECT ID_P
FROM A
GROUP BY ID_P
HAVING COUNT(ID_P) > 1);
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET FINISHED = 1;
OPEN CURRENT_ROW;
GET_ACTION:
LOOP
FETCH CURRENT_ROW INTO CURRENT_ROW_ID;
IF FINISHED = 1 THEN
LEAVE GET_ACTION;
END IF;
SET #CURRENT_P_ID := (SELECT ID_P FROM A WHERE ID = CURRENT_ROW_ID);
SELECT a.ID_U, a.ID_R, a.A, a.FROMDATE, a.TODATE
INTO #ID_U, #ID_R, #A, #FROM_DATE, #TO_DATE
FROM ASSIG a
WHERE a.ID_G = #CURRENT_P_ID; # <- Query that returns 0 rows and terminates the cursor
IF (#ID_U IS NOT NULL) THEN
SET #ASSIG_ID := GENERATE_ID();
INSERT INTO ASSIG
VALUES (#ASSIG_ID,
#G_ID,
#ID_U,
#ID_R,
#A,
#FROM_DATE,
#TO_DATE);
END IF;
UPDATE A
SET ID_P = #G_ID
WHERE ID = CURRENT_ROW_ID;
END LOOP GET_ACTION;
CLOSE CURRENT_ROW;
END
$$
DELIMITER ;

error in stored procedure ...into keyword

Two tables Borrower(rollno,name,bookissue_date) and Fine(rollno,name,amount)
delimiter //
create procedure student( in roll_no int,in Nameofbook varchar(40))
begin
declare Dateofiss1 date;
Declare cur cursor for
select Dateofiss from Borrower where Roll_no = roll into Dateofiss1;
OPEN cur;
fetch cur into Dateofiss1
if(datediff(sysdate(),Dateofiss1)<15) then varchar(20))
update Borrower set status='R'where Roll_no=roll_no
elseif(datediff(sysdate(),Dateofiss1)>=15)and datediff (sysdate(),Dateofiss1<30)
SET FINEAMOUNT=5*(datediff(sysdate(),Dateofiss1)-15)
insert into Fine(Roll_no,Date,amount)values(rollno,sysdate,fineamount);
update.borrower set status='R' where Roll_no='rollno';
elseif (datediff(sysdate(),Dateofiss1)>30)
SET FINEAMOUNT=50*(datediff(sysdate(),Dateofiss1)-15)
insert into Fine(Roll_no,Date,amount)values(rollno,sysdate,fineamount);
update.borrower set status='R' where Roll_no='rollno';
close cur;
end if
select * from Borrower;
elect * from Fine;
end
You have a number of syntax errors.
You have an extraneous varchar(20)) in the first if statement.
You're missing THEN in the ELSEIF statements.
You wrote update.borrower instead of update borrower.
You have roll_no in quotes in some of your update statements.
The roll_no parameter is the same as a table column, since column names are case-insensitive. The condition where Roll_no = roll_no will match every row because of this. Give the parameter a different name.
In a SELECT, the INTO clause goes after FROM, not at the end.
There's no need to use a cursor if you're using SELECT INTO. Just execute the query and it will set the variable.
You can also simplify the code by putting the date difference in a variable, so you don't have to repeatedly calculate it. And in the ELSEIF you don't need to test >= 15, since you'll only get there if the < 15 test failed.
The UPDATE statement is the same in all conditions, so it doesn't need to be in the IF at all.
delimiter //
create procedure student( in p_roll_no int,in Nameofbook varchar(40))
begin
declare Dateofiss1 date;
declare diff INT;
select Dateofiss from Borrower into Dateofiss1 where Roll_no = p_roll_no;
OPEN cur;
SET diff = datediff(sysdate(),Dateofiss1)
IF diff BETWEEN 15 AND 29 THEN
SET FINEAMOUNT= 5 * (diff - 15)
insert into Fine(Roll_no,Date,amount)values(rollno,sysdate,fineamount);
else
SET FINEAMOUNT= 50 * (diff - 15)
insert into Fine(Roll_no,Date,amount)values(rollno,sysdate,fineamount);
end if
update Borrower set status='R'where Roll_no=p_roll_no
select * from Borrower;
select * from Fine;
end

mysql. Stored Procedure Error 1328

This is really baffling me. I am converting a simple procedure from informix into mysql. What it basically does is tell me what the next event is from an event table and a calendar table. In informix the procedure is simple.
FOREACH
SELECT date,weekno,event
INTO l_date,l_week,l_event
FROM event,calendar
WHERE dayno = dayno
AND date = l_today
AND start >= l_now
UNION
SELECT date,weekno,event
FROM event,calendar
WHERE dayno = dayno
AND date > l_today
UNION
SELECT TODAY,9999,9999
FROM event,calendar
WHERE dayno = dayno
AND event = (SELECT MAX(event) FROM event)
ORDER BY 3
if l_event = 9999 then <error> end if;
EXIT FOREACH
END FOREACH
So basically the query finds the next event and returns it. l_today and l_event are parameters that are passed. So on to the mysql version.
looper: BEGIN
DECLARE curs1 CURSOR FOR
SELECT CONCAT("SELECT date, weekno, event FROM event INNER JOIN calendar ON dayno = dayno",
" WHERE date = '", lv_today ,"' AND start >= '", lv_time ,"'",
" UNION SELECT date, weekno, event FROM event INNER JOIN calendar ON dayno = dayno WHERE date > '", lv_today ,"'",
" UNION SELECT DATE(NOW()) AS date, 9999 AS weekno, 9999 AS event FROM event INNER JOIN calendar ON dayno = dayno",
" WHERE (SELECT MAX(event) FROM event) ORDER BY event ");
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done := TRUE;
OPEN curs1;
loop1: LOOP
FETCH curs1 INTO ldate, lweek, levent;
SELECT ldate, lweek, levent;
LEAVE looper;
END LOOP loop1;
END;
I haven't checked that the rest of the methodology works because I get this error:
Incorrect number of FETCH variables.
Does this mean that I have declare a different variable for each of the query returns? I am new to mysql. If this is the case what would be the best way to solve this conundrum? I have also changed to column and table names.
Many thanks
looper: BEGIN
DECLARE curs1 CURSOR FOR
SELECT eve_date, dia_weekno, eve_event
FROM game_event
INNER JOIN stan_calendar ON eve_abs_dayno = dia_abs_dayno
WHERE eve_date = lv_today
AND eve_start >= lv_time
UNION
SELECT eve_date, dia_weekno, eve_event
FROM game_event
INNER JOIN stan_calendar ON eve_abs_dayno = dia_abs_dayno
WHERE eve_date > lv_today
UNION SELECT DATE(NOW()) AS eve_date, 9999 AS dia_weekno, 9999 AS eve_event
FROM game_event
INNER JOIN stan_calendar ON eve_abs_dayno = dia_abs_dayno
WHERE (SELECT MAX(eve_event) FROM game_event) ORDER BY eve_event;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done := TRUE;
OPEN curs1;
curs_loop: LOOP
FETCH curs1 INTO lv_date, lv_week, lv_event;
SELECT lv_date, lv_week, lv_event;
LEAVE looper;
CLOSE curs1;
END LOOP curs_loop;
Thank you for answering my question, I have put it back to how I thought it was... and it now works. Here is the loop in full.
https://dev.mysql.com/doc/refman/5.7/en/fetch.html The number of columns retrieved by the SELECT statement must match the number of output variables specified in the FETCH statement so yes but in fact you are only selecting 1 concatenated string - I think your first problem is with the select syntax which doesn't need the concat, the brackets or the quotes (unless you are trying to create a prepared statement for some reason - and even if you were I doubt if the code would be correct)
Simple Cursor
DROP PROCEDURE IF EXISTS EC;
DELIMITER $$
CREATE PROCEDURE `EC`(
IN `inemp_no` varchar(255)
)
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
LOOPER:begin
DECLARE done INT DEFAULT FALSE;
declare ename varchar(20);
declare esalary int default 0;
declare emp_cursor CURSOR FOR
SELECT last_name,salary FROM employees where emp_no= inemp_no ;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
open emp_cursor;
read_loop: loop
fetch emp_cursor into ename,esalary;
if done then leave read_loop; end if;
insert into debug_table (msg) values(concat('employee:',ename,' earns:',esalary));
end loop;
close emp_cursor;
end $$
DELIMITER ;
MariaDB [sandbox]> truncate table debug_table;
Query OK, 0 rows affected (0.22 sec)
MariaDB [sandbox]> call ec(2);
Query OK, 0 rows affected (0.03 sec)
MariaDB [sandbox]> select * from debug_table;
+----+--------------------------+------+
| id | msg | MSG2 |
+----+--------------------------+------+
| 1 | employee:BBB earns:39500 | NULL |
+----+--------------------------+------+
1 row in set (0.00 sec)

MySQL stored procedure pass select as parameter

could you please give me an advice how to CALL prcd with SELECT results? Or advice me pls better solution.. I am open minded to all working solution
I have a procedure to control inserting data ...
CREATE PROCEDURE control_insert (
)
And I need to pass data from SELECT results to procedure ...
SELECT t.c1, t.c2
FROM table t1
LEFT JOIN other_table t2
ON t1.id = t2.id
WHERE 1=1
The point is, I need to get some data via SELECT (around 6 tables joined to the base table) and I need to do control for each row before insert.. each row should meet some conditions .. if it doesn't meet them, it should just skip it and process next one ...
The procedure should look like:
CREATE PROCEDURE control_insert (
IN v_c1 INT,
IN v_c2 INT
)
BEGIN
IF v_c1 > 1 THEN
INSERT INTO controlled_table (id, type) VALUES (v_c1, v_c2);
ELSE
/* do nothing */
END IF;
END;
CALL control_insert ( SELECT .... );
Could you help me with that? Is there any possibility to do this via MySQL? I can write a PERL skript, but I want to avoid this type of solution ... I just one to do it only in MySQL way
Thank you
EDIT1: I need to check if ID of the SELECT result and LABEL is already in this table for specific date ... this code above is only an example to demonstrate the situation
SOLUTION
I've found the solution ... so for the other visitors:
calling procedure:
CALL controlInsert();
procedure body:
CREATE PROCEDURE controlInsert()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE v_id INT;
DECLARE v_id_dupl INT;
DECLARE v_label INT;
DECLARE v_date DATE;
DECLARE v_type VARCHAR(100);
DECLARE v_category VARCHAR(255);
DECLARE v_user VARCHAR(255);
DECLARE v_country VARCHAR(255);
DECLARE c1 CURSOR FOR SELECT id, label, date, type, category, user, country FROM t1 LEFT JOIN ... /* whole select with 6 joins ended by ; */
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
## open cursor
OPEN c1;
## loop through the cursor
read_loop: LOOP
## fetch cursor into variables
FETCH c1 INTO v_id , v_label, v_date, v_type, v_category, v_user, v_country;
## check if there is any record
IF done THEN
LEAVE read_loop;
END IF;
## get count of existing records
SELECT count(*) INTO v_id_dupl
FROM
WHERE 1=1
AND id = v_id
AND label= v_label
AND date = v_date;
## if v_id_dupl = 0 => no rows found (ok to load)
IF (v_id_dupl = 0) THEN
INSERT INTO target_table (id, label, date, type, category, user, country)
VALUES (v_id , v_label, v_date, v_type, v_category, v_user, v_country);
END IF;
END LOOP;
CLOSE c1;
END
If that is all your stored procedure is doing, then you don't actually need it. You can do the whole thing in a single statement:
INSERT INTO controlled_table (id, type)
SELECT t.c1, t.c2
FROM table t1
LEFT JOIN other_table t2 ON t1.id = t2.id
WHERE something = somethingElse
AND t.c1 > 1
Essentially, I've just combined your original query with the INSERT statement in your procedure.
If your procedure is more complex and needs to do multiple operations on each row, then you should look into using a cursor.

SSRS Pivot Expression Inside Stored Procedure with HashTemp Not Running

While Working With SSRS, Today, i got 2 Problems 1 is Still remain Unsolved and Im going to Post Another Freaking Problem :) Well, Problem is : I've an Stored Procedure, Which Create an #Temp and Finally Use that data with PIVOT Expression. And, Stored Procedure itself runs Fine inside SSMS and From Visual Basic 6.0 too, but While Using that Procedure from SSRS report it shows an error at the Pivot Expression. Following are the Screen Shots, Please Review and Suggest me an Idea.
Here is an Stored Procedure :
ALTER PROCEDURE [dbo].[S_NRB_9_8_REPORT](#SCRCODE AS VARCHAR(20),
#CUREDATE VARCHAR(10),
#DTNAME VARCHAR(50),
#BR_CODE VARCHAR(50),
#CENTRALIZED VARCHAR(3))
WITH RECOMPILE
AS BEGIN
SET NOCOUNT ON;
DECLARE #BRCODE VARCHAR(3)
DECLARE #DTBASE VARCHAR(50)
DECLARE #CAT_TYPE_CODE VARCHAR(50)
DECLARE #AC_TYPE_SUB_TYPE_NAME VARCHAR(200)
DECLARE #CODESTR VARCHAR (1000)
DECLARE #CODESTR1 VARCHAR (1000)
SET #BRCODE=''
SET #DTBASE=''
SET #AC_TYPE_SUB_TYPE_NAME=''
SET #CODESTR=''
SET #CODESTR1=''
SELECT TOP 1 #CAT_TYPE_CODE=CAT_TYPE_CODE FROM REPORT_CAT_TYPE_CODE WHERE SCREEN_CODE =#SCRCODE
IF #CAT_TYPE_CODE='' OR #CAT_TYPE_CODE IS NULL
RETURN
CREATE TABLE [dbo].[#TEMPACTYPE](
[BR_CODE] [varchar](3) NULL,
[CN] [varchar](50) NULL,
[CS] [varchar](50) NULL,
[BAL] decimal(18, 2) NULL,
[AC_TYPE_SUB_TYPE_NAME] [varchar](50) NULL
) ON [PRIMARY]
IF LEN(#BR_CODE)>0
EXEC('DECLARE CUR INSENSITIVE CURSOR FOR SELECT BR_CODE FROM '+#DTBASE+'.DBO.BRANCH B (NOLOCK) WHERE BR_CODE='''+#BR_CODE+''' AND INTEGRATED=''YES'' AND APPROVED=''YES'' ORDER BY BR_CODE')
ELSE
EXEC('DECLARE CUR INSENSITIVE CURSOR FOR SELECT BR_CODE FROM '+#DTBASE+'.DBO.BRANCH B (NOLOCK) WHERE INTEGRATED=''YES'' AND APPROVED=''YES'' ORDER BY BR_CODE')
OPEN CUR
FETCH NEXT FROM CUR INTO #BRCODE
While ##FETCH_STATUS = 0
Begin
IF #CENTRALIZED='YES'
SET #DTBASE = #DTNAME
ELSE
SET #DTBASE = Left(#DTNAME, 13) + #BRCODE
EXEC('INSERT INTO #TEMPACTYPE
SELECT '''+#BRCODE+''' AS BR_CODE,T1.CAT_NAME AS CN,T1.CODES AS CS,SUM(T1.C_BAL)AS BAL,T1.AC_TYPE_SUB_TYPE_NAME FROM
(SELECT C_BAL,ATST.AC_TYPE_SUB_TYPE_NAME,CD.CAT_NAME,CD.CODE_STRING AS CODES
FROM
(SELECT AC_GROUP_CODE,CUR_CODE,GL_CODE FROM '+#DTBASE+'.dbo.AC_GROUP_GL_MAP WHERE NAMED_AC_CODE =''0301'') MAP,
(SELECT AC_GROUP_CODE,CUR_CODE,AC_NO FROM '+#DTBASE+'.dbo.DEPOSIT_AC_MAST WHERE BR_CODE='''+#BRCODE+''') DAM,
(SELECT TRAN_DATE,AC_NO,GL_CODE,PRODUCT_CODE,SUM(CLS_BAL) AS C_BAL FROM '+#DTBASE+'.dbo.AC_BAL WHERE BR_CODE='''+#BRCODE+''' GROUP BY TRAN_DATE,AC_NO,GL_CODE,PRODUCT_CODE) WD,
(SELECT * FROM '+#DTBASE+'.dbo.CAT_CODING where BR_CODE='''+#BRCODE+''' AND CAT_TYPE_CODE ='''+#CAT_TYPE_CODE+''') AS CC,
(SELECT * FROM '+#DTBASE+'.dbo.AC_TYPE_SUB_TYPE) AS ATST,
(SELECT * FROM '+#DTBASE+'.dbo.AC_GROUP) AS AG,
(SELECT * FROM '+#DTBASE+'.dbo.CAT_DETL) AS CD
WHERE
DAM.AC_GROUP_CODE =MAP.AC_GROUP_CODE
AND DAM.CUR_CODE =MAP.CUR_CODE
AND WD.GL_CODE =MAP.GL_CODE
AND CC.ENTITY_NO=DAM.AC_NO
AND ATST.AC_TYPE_CODE=AG.AC_TYPE_CODE
AND ATST.AC_TYPE_SUB_TYPE_CODE=AG.AC_TYPE_SUB_TYPE_CODE
AND AG.AC_GROUP_CODE=DAM.AC_GROUP_CODE
AND CD.CAT_TYPE_CODE=CC.CAT_TYPE_CODE
AND CD.CAT_CODE=CC.CAT_CODE
AND CD.CAT_TYPE_CODE='''+#CAT_TYPE_CODE+'''
AND WD.TRAN_DATE = (SELECT MAX(TRAN_DATE) FROM '+#DTBASE+'.dbo.AC_BAL WHERE BR_CODE ='''+#BRCODE+''' AND AC_NO = DAM.AC_NO AND TRAN_DATE <='''+#CUREDATE+''' AND GL_CODE=MAP.GL_CODE)
AND DAM.AC_NO=WD.AC_NO
UNION ALL
SELECT 0,ATST.AC_TYPE_SUB_TYPE_NAME,CAT_NAME,CODE_STRING AS CODES FROM '+#DTBASE+'.dbo.CAT_DETL AS CD,'+#DTBASE+'.dbo.AC_TYPE_SUB_TYPE AS ATST
WHERE CAT_TYPE_CODE='''+#CAT_TYPE_CODE+''' AND CAT_CODE NOT IN (SELECT CAT_CODE FROM '+#DTBASE+'.dbo.CAT_CODING WHERE BR_CODE='''+#BRCODE+''' AND CAT_TYPE_CODE='''+#CAT_TYPE_CODE+''')
AND ATST.AC_TYPE_CODE=''03''
) T1
GROUP BY T1.AC_TYPE_SUB_TYPE_NAME,CAT_NAME,CODES
ORDER BY CODES
')
FETCH NEXT FROM CUR INTO #BRCODE
END
DEALLOCATE CUR
DECLARE CUR INSENSITIVE CURSOR FOR SELECT DISTINCT AC_TYPE_SUB_TYPE_NAME FROM #TEMPACTYPE
OPEN CUR
Fetch Next from CUR Into #AC_TYPE_SUB_TYPE_NAME
While ##FETCH_STATUS = 0
Begin
IF #CODESTR =''
BEGIN
SET #CODESTR = 'ISNULL(['+#AC_TYPE_SUB_TYPE_NAME+'],0) AS ['+#AC_TYPE_SUB_TYPE_NAME+']'
SET #CODESTR1 = '['+#AC_TYPE_SUB_TYPE_NAME+']'
END
ELSE
BEGIN
SET #CODESTR = #CODESTR+',ISNULL(['+#AC_TYPE_SUB_TYPE_NAME+'],0) AS ['+#AC_TYPE_SUB_TYPE_NAME+']'
SET #CODESTR1 = #CODESTR1+',['+#AC_TYPE_SUB_TYPE_NAME+']'
END
Fetch Next from CUR Into #AC_TYPE_SUB_TYPE_NAME
END
DEALLOCATE CUR
EXEC ('Select CS,CN,'+#CODESTR+',TOTAL
from (Select CN,CS,BAL,[AC_TYPE_SUB_TYPE_NAME] from #TEMPACTYPE) ps pivot (SUM([BAL])
for [AC_TYPE_SUB_TYPE_NAME] in ('+#CODESTR1+',TOTAL)) pvt
Order by CS')
DROP TABLE #TEMPACTYPE
END
GO
And, the Dataset Design Panel :
But, Stored Procedure Runs Well inside SSMS :
Im Using SSRS 2008 R2.
Please Help me out.
And, Thanks In Advance.
Try validating that you are passing the same parameter values between the report and SSMS. You can do this by clicking Edit Query and inputting the actual parameter values. If the Edit Query window returns proper results, then you are probably passing different values to the stored procedure.