问题
I'm writing an sql script in Firebird for an assignment. First, I have to create a 2 column table and add some values (the values aren't supposed to do anything yet)
--Create the table
create table salary_class (
class varchar(5),
occurrence int ) ;
commit work;
--Add Values to our table
insert into salary_class (class, occurrence)
values ('ELITE', 0);
insert into salary_class (class, occurrence)
values ('HIGH', 0);
insert into salary_class (class, occurrence)
values ('MID', 0);
insert into salary_class (class, occurrence)
values ('LOW', 0);
commit work;
After that worked is committed, I create a procedure. It is supposed to return a certain string based on the number that is passed into it.
--Create f_class procedure
set term # ;
create procedure f_class(salary SALARY)
returns (lv VARCHAR(10)) as
begin
--If statements for each occurrence level
if (salary <= 39999) then
lv = 'LOW';
suspend;
if (salary <= 67999) then
lv = 'MID';
suspend;
if (salary <= 99999) then
lv = 'HIGH';
suspend;
if (salary >= 100000) then
lv = 'ELITE';
suspend;
end#
set term ; #
--Demonstrate that f_class function works correctly
select lv from f_class(20000);
select lv from f_class(67999);
select lv from f_class(68000);
select lv from f_class(120000);
Calling the function gives me
LV
null
null
null
ELITE
But it's supposed to give me
LV
LOW
MID
HIGH
ELITE
If anyone could shine some light on this, it would be much appreciated. Been pulling my hair out over the Firebird manual the past 2 days.
回答1:
You have multiple problems in your code. The first problem is that you use suspend
unconditionally, which means that each invocation of the stored procedure returns 4 rows, which depending on the condition may contain a null
value, or a previous value.
This doesn't seem what you expect, as the expected output of your question seems to match the expectation for each individual salary, while the actual output is the output of the last statement (select lv from f_class(120000);
).
The second problem is that you use individual if
statements, which leads to multiple conditions being evaluated (eg value 1 will returnlow
, mid
and high
(2x), and value 67999 will return null
, mid
and high
(2x), etc).
To solve your problems there are a few solutions:
Use a chained if .. then .. else:
if (salary <= 39999) then lv = 'LOW'; else if (salary <= 67999) then lv = 'MID'; else if (salary <= 99999) then lv = 'HIGH'; else if (salary >= 100000) then lv = 'ELITE'; suspend;
The single
suspend
will also prevent the output of multiple rows.Replace the
if
-statements with a searched case:lv = case when salary <= 39999 then 'LOW' when salary <= 67999 then 'MID' when salary <= 99999 then 'HIGH' when salary >= 100000 then 'ELITE' end; suspend;
You can also replace the last
when salary >= 100000 then 'ELITE'
withelse 'ELITE'
However you describing this as a function in your question makes me think that this might be the wrong solution altogether. Stored procedures are not functions, they are procedures that optionally return values or - with suspend
- produce dynamic 'tables' (a result set). If you need a real function, and you are using Firebird 3, then use stored functions:
create function f_class(salary SALARY) returns varchar(10)
as
begin
return case
when salary <= 39999 then 'LOW'
when salary <= 67999 then 'MID'
when salary <= 99999 then 'HIGH'
when salary >= 100000 then 'ELITE'
end;
end
You can then use it like
select f_class(120000) from rdb$database;
The use of rdb$database
is purely for illustration here, a stored function can be used anywhere a normal SQL function can be used.
来源:https://stackoverflow.com/questions/49962078/in-firebird-how-do-i-write-multiple-if-statements-in-a-procedure