I'm currently getting this error:
Msg 217, Level 16, State 1, Line 127
Maximum stored procedure, function, trigger, or view nesting level exceeded (limit 32)
How can I minimize the nesting level? I did some research and saw that someone had used go each end but that didn't work for me.
--Function: StateFilingStatus
create function dbo.GetStateFilingStatus(#EmpFederalFilingStatus char(1), #EmpTransferState char(2))
returns char(1)
as
begin
declare #StateFilingStatus char;
if (#EmpTransferState = 'MS')
begin
if (#EmpFederalFilingStatus = 'S')
set #StateFilingStatus = 'A';
else
set #StateFilingStatus = 'M';
end
else if (#EmpTransferState = 'NJ')
begin
if (#EmpFederalFilingStatus = 'S')
set #StateFilingStatus = 'B';
else
set #StateFilingStatus = 'A';
end
else if (#EmpTransferState = 'AZ')
begin
if (#EmpFederalFilingStatus = 'S')
set #StateFilingStatus = 'A';
else
set #StateFilingStatus = 'B';
end
else if (#EmpTransferState = 'CT')
begin
if (#EmpFederalFilingStatus = 'S')
set #StateFilingStatus = 'F';
else
set #StateFilingStatus = 'M';
end
else if (#EmpTransferState = 'DC')
begin
if (#EmpFederalFilingStatus = 'S')
set #StateFilingStatus = 'S';
else
set #StateFilingStatus = 'Y';
end
else
begin
if (#EmpFederalFilingStatus = 'S')
set #StateFilingStatus = 'S';
else
set #StateFilingStatus = 'M';
end
return (select dbo.GetStateFilingStatus(EmpFederalFilingStatus, EmpTransferState) as StateFilingStatus
from EmployeeTransfers)
end
go
select dbo.GetStateFilingStatus('M','NJ') as StateFilingStatus
Currently, your nesting problem is from incorrectly formed return.
Instead of:
return(
select dbo.GetStateFilingStatus(EmpFederalFilingStatus, EmpTransferState) as StateFilingStatus
from EmployeeTransfers
)
You would use:
return #StateFilingStatus;
rextester demo: http://rextester.com/DJM36125
--Function: StateFilingStatus
create function dbo.GetStateFilingStatus(
#EmpFederalFilingStatus char(1)
, #EmpTransferState char(2)
)
returns char(1) as
begin;
declare #StateFilingStatus char(1);
if (#EmpTransferState = 'MS')
begin;
if (#EmpFederalFilingStatus = 'S')
set #StateFilingStatus = 'A';
else
set #StateFilingStatus = 'M';
end;
else
if (#EmpTransferState = 'NJ')
begin;
if (#EmpFederalFilingStatus = 'S')
set #StateFilingStatus = 'B';
else
set #StateFilingStatus = 'A';
end;
else
if (#EmpTransferState = 'AZ')
begin;
if (#EmpFederalFilingStatus = 'S')
set #StateFilingStatus = 'A';
else
set #StateFilingStatus = 'B';
end;
else
if (#EmpTransferState = 'CT')
begin;
if (#EmpFederalFilingStatus = 'S')
set #StateFilingStatus = 'F';
else
set #StateFilingStatus = 'M';
end;
else
if (#EmpTransferState = 'DC')
begin;
if (#EmpFederalFilingStatus = 'S')
set #StateFilingStatus = 'S';
else
set #StateFilingStatus = 'Y';
end;
else
begin
if (#EmpFederalFilingStatus = 'S')
set #StateFilingStatus = 'S';
else
set #StateFilingStatus = 'M';
end;
return #StateFilingStatus;
end;
go
select StateFilingStatus = dbo.GetStateFilingStatus('','NJ');
returns A
And since this is a scalar function, you would query with it using:
select
et.EmpFederalFilingStatus
, StateFilingStatus = dbo.GetStateFilingStatus(et.EmpFederalFilingStatus,et.EmpTransferState)
from EmployeeTransfers et
Scalar functions like this can cause horrible performance issues. Whenever possible, functions should be written as in-line table valued functions.
If this is anything except for a learning exercise, I would recommend using a crosswalk table (as my other answer explains).
Reference:
When is a SQL function not a function? "If it’s not inline, it’s rubbish." - Rob Farley
Inline Scalar Functions - Itzik Ben-Gan
Scalar functions, inlining, and performance: An entertaining title for a boring post - Adam Machanic
TSQL User-Defined Functions: Ten Questions You Were Too Shy To Ask - Robert Sheldon
Instead of handling all of this on a case by case basis, why not create a crosswalk table?
create table Filing_State_xwalk (
TransferState char(2) not null
, FederalStatus char(1) not null
, StateStatus char(1) not null
, constraint pk_Filing_State_xwalk
primary key (TransferState, FederalStatus)
);
insert into Filing_State_xwalk values
('MS','S','A')
,('MS',' ','M')
,('NJ','S','B')
,('NJ',' ','A')
,('AZ','S','A')
,('AZ',' ','M')
,('CT','S','F')
,('CT',' ','M')
,('DC','S','S')
,('DC',' ','Y');
And use it in a procedure like so:
set #StateFilingStatus = (
select StateStatus
from Filing_State_xwalk
where TransferState = #EmpTransferState
and FederalStatus = coalesce(#EmpFederalFilingStatus,' ')
);
Or join to it directly from queries instead of calling a function.
Related
I'm getting a SYNTAX error attempting to create a mySQL function to parse a string. It's probably something simple that I'm not realizing given that I have more experience creating FN's with SQL then MySQL.
Here's my function:
CREATE FUNCTION fn_parse_string (string1 varchar(2048),datapoint1 varchar(20),delimiter1
varchar(1))
RETURNS varchar(60) DETERMINISTIC
BEGIN
DECLARE datareturn1 VARCHAR(60)
IF INSTR(string1, datapoint1) > 0
THEN
SET datareturn1 = SUBSTRING_INDEX(SUBSTRING(string1,
INSTR(string1, datapoint1) + LENGTH(datapoint1),
LENGTH(string1)),
delimiter1,
1)
ELSEIF IFNULL(datapoint1,'') = ''
THEN
SET datareturn1 = 'Blank Field'
ELSE SET datareturn1 = 'N/A'
END IF;
RETURN (datareturn1);
END
It seems that some semicolons missing, try it in this way please:
CREATE FUNCTION fn_parse_string (string1 varchar(2048),datapoint1 varchar(20),delimiter1
varchar(1))
RETURNS varchar(60) DETERMINISTIC
BEGIN
DECLARE datareturn1 VARCHAR(60);
IF INSTR(string1, datapoint1) > 0
THEN
SET datareturn1 = SUBSTRING_INDEX(SUBSTRING(string1,
INSTR(string1, datapoint1) + LENGTH(datapoint1),
LENGTH(string1)),
delimiter,
1);
ELSEIF IFNULL(datapoint1,'') = ''
THEN
SET datareturn1 = 'Blank Field';
ELSE SET datareturn1 = 'N/A';
END IF;
RETURN (datareturn1);
END
i want my function to return "INC" when put "INC" inside the function parameters
SELECT getEquivalentGrade('INC');
Output: INC
DELIMITER $$
USE `nmsc_scholarship_db`$$
DROP FUNCTION IF EXISTS `getEquivalentGrade`$$
CREATE DEFINER =`root`#`localhost` FUNCTION `getEquivalentGrade`(grade CHAR(5))
RETURNS CHAR(5)
CHARSET latin1
BEGIN
DECLARE equivalent_grade CHAR(5);
IF (grade > 100)
THEN
SET equivalent_grade = '1';
ELSEIF (grade < 69)
THEN
SET equivalent_grade = '5';
ELSEIF (grade = 'INC')
THEN
SET equivalent_grade = grade;
ELSE
SET equivalent_grade = (SELECT equivalent_grade.`equivgrade`
FROM equivalent_grade
WHERE equivalent_grade.`fromgrade` <= grade AND equivalent_grade.`tograde` >= grade);
END IF;
RETURN equivalent_grade;
END$$
DELIMITER ;
now, if i will execute this function, this is what i get.
SELECT getEquivalentGrade('INC');
Output: 5
You should move the INC to the TOP
IF (grade='INC') THEN
SET equivalent_grade = grade;
ELSEIF (grade > 100) THEN
SET equivalent_grade = '1';
ELSEIF (grade < 69) THEN
SET equivalent_grade = '5';
ELSE
SET equivalent_grade = (SELECT equivalent_grade.`equivgrade` FROM equivalent_grade WHERE equivalent_grade.`fromgrade`<= grade AND equivalent_grade.`tograde`>= grade);
And you should research how IFELSE work.
Condition was working like it will stop/goto ENDIF.. IF** the condition true was meet, or they will keep finding till the latest IF
I've created a procedure in my DB of a veterinary clinic that shows what is: the first date, the first time available with a veterinarian authorized to perform the service requested (there mustn't be other appointments booked at the same time). However when I call this procedure the cursor stops because the value of eof is 1, but it didn't really see all the records: the cursor leaves the loop before the end of rows! I can not understand why.
here is the code:
DELIMITER //
DROP PROCEDURE IF EXISTS first_booking_available //
CREATE PROCEDURE first_booking_available(IN Perf VARCHAR(30), IN DateP DATE)
BEGIN
DECLARE IdV, eof INTEGER;
DECLARE Dat DATE;
DECLARE i, TimeB, End TIME;
DECLARE vet CURSOR FOR E.Id_vet, W.Date, S.Start_time, S.End_time
FROM Enabled E, Work W, WorkShift S
WHERE E.Code_performance = Perf AND W.Id_vet = E.Id_vet AND S.Code = W.Code_workshift AND W.Date >= DateP ORDER BY W.Date, S.Start_time;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET eof = 1;
SELECT Duration INTO #Duration FROM Perfomance WHERE Code = Perf;
SET #Start_time = NULL;
OPEN vet;
read_loop: LOOP
FETCH vet INTO IdV, Dat, TimeB, End;
IF (eof = 1 OR #Start_time IS NOT NULL) THEN
LEAVE read_loop;
END IF;
SET i = TimeB;
WHILE i < End AND #Start_time IS NULL DO
SET #P = NULL;
SET #F = NULL;
SELECT ADDTIME(ADDTIME(B.Start_time, P.Duration), '00:01:00') INTO #P
FROM Booking B, Performance P
WHERE P.Code = B.Code_performance AND B.Date = Dat AND B.Id_vet = IdV AND B.Start_time = i;
SELECT ADDTIME(ADDTIME(B.Start_time, P.Duration), '00:01:00') INTO #F
FROM Booking B, Performance P
WHERE P.Code = B.Code_performance AND B.Date = Dat AND B.Id_vet = IdV AND B.Start_time BETWEEN i AND ADDTIME(i, #Duration) ORDER BY ADDTIME(B.Start_time, P.Duration) DESC LIMIT 1;
IF #P IS NOT NULL THEN
SET i = #P;
END IF;
IF #F IS NOT NULL THEN
SET i = #F;
END IF;
IF ADDTIME(i, #duration) > End THEN
SET i = End;
END IF;
IF ((#P IS NULL) AND (#F IS NULL) AND (i != End)) THEN
SET #Start_Time = i;
END IF;
END WHILE;
IF #Start_Time IS NOT NULL THEN
SET #Id_vet = IdV;
SET #Date = Dat;
END IF;
END LOOP;
CLOSE vet;
IF #Start_Time IS NULL THEN
SIGNAL sqlstate '99994'
SET MESSAGE_TEXT = 'there is no availability !';
END IF;
END //
DELIMITER ;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET eof = 1;
is mean your query has no result. It is not apply just cursor, another select query too.
SELECT ADDTIME(ADDTIME(B.Start_time, P.Duration), '00:01:00') INTO #P
FROM Booking B, Performance P
WHERE P.Code = B.Code_performance AND B.Date = Dat AND B.Id_vet = IdV AND B.Start_time = i;
SELECT ADDTIME(ADDTIME(B.Start_time, P.Duration), '00:01:00') INTO #F
FROM Booking B, Performance P
WHERE P.Code = B.Code_performance AND B.Date = Dat AND B.Id_vet = IdV AND B.Start_time BETWEEN i AND ADDTIME(i, #Duration) ORDER BY ADDTIME(B.Start_time, P.Duration) DESC LIMIT 1;
this query has no result. HANDLER catch them. and leave cursor.
I have write one function but getting this error Not allowed to return a result set from a function
DELIMITER $$
CREATE FUNCTION getTestFunction
(
p_ParentID int,
p_ListName nvarchar(50),
p_Type nvarchar(50),
p_Count int
)
RETURNS nvarchar(2000)
BEGIN
DECLARE p_KeyValue nvarchar(2000);
DECLARE p_ListValue nvarchar(2000);
DECLARE p_TextValue nvarchar(2000);
DECLARE p_ReturnValue nvarchar(2000);
DECLARE p_Key nvarchar(2000);
IF p_ParentID = 0 THEN
IF p_Count = 0 THEN
SET p_ReturnValue = '';
ELSE
SET p_ReturnValue = p_ListName;
END IF;
ELSE
SELECT p_KeyValue = ListName + '.' + Value
FROM ListsTable
WHERE EntryID = p_ParentID LIMIT 1 ;
RETURN p_ReturnValue;
If p_Type = 'ParentKey' Or (p_Type = 'ParentList' AND p_Count > 0) THEN
SET p_ReturnValue = p_KeyValue;
ELSE
IF p_Type = 'ParentList' THEN
SET p_ReturnValue = p_ListValue;
ELSE
SET p_ReturnValue = p_TextValue;
END IF;
END IF;
IF p_Count > 0 THEN
If p_Count = 1 AND p_Type = 'ParentList' THEN
SET p_ReturnValue = p_ReturnValue + ':' + p_ListName;
ELSE
SET p_ReturnValue = p_ReturnValue + '.' + p_ListName;
END IF;
END IF;
END IF;
RETURN p_ReturnValue;
END$$
DELIMITER ;
You want to assign the result of a query to a variable, but in fact you're just selecting. That's why MySQL's complaining.
You have to change this
SELECT p_KeyValue = ListName + '.' + Value
FROM ListsTable
WHERE EntryID = p_ParentID LIMIT 1 ;
to
SELECT CONCAT(ListName, '.', `Value`)
INTO p_KeyValue
FROM ListsTable
WHERE EntryID = p_ParentID LIMIT 1 ;
And you should add an ORDER BY. A LIMIT without ORDER BY doesn't make sense, since there's no guaranteed order in a relational database.
Mysql complains about SELECT statement in your function,
probably it understands SELECT p_KeyValue = ListName + '.' + Value as comparison
change it to
SELECT CONCAT(ListName, '.', Value) INTO p_KeyValue
I'm trying to create a function that will produce a string indicating the size of a book, but it is not working. Any suggestions?
delimiter #
Drop function if exists a_testbed.BookSize #
Create function a_testbed.BookSize(book int)
Returns varchar(10)
Begin
Declare v_pages int;
Declare in_book varchar(10);
if(v_pages <= 200) then
Set in_book = 'mini';
elseif(v_pages <= 500) then
Set in_book = 'small';
elseif(v_pages <= 1500) then
Set in_book = 'medium';
elseif(v_pages > 1500) then
Set in_book = 'large';
else
Set in_book ='Invalid Input';
end if;
Return in_book ;
end; #
Trying to produce output as a sample:
select a_testbed.BookSize(200)#
Well first off, in your final else conditional, you set the return value to a value more than 10 characters.
Create function BookSize(book int)
Returns varchar(10)
Begin
Declare in_book varchar(10);
if(book <= 200) then
Set in_book = 'mini';
elseif(book <= 500) then
Set in_book = 'small';
elseif(book <= 1500) then
Set in_book = 'medium';
elseif(book > 1500) then
Set in_book = 'large';
else
Set in_book ='Invalid';
end if;
Return in_book ;
END
sqlFiddle here, I did it because i was curious on how to create a function :)