The function created with compilation errors - sql

I cant compile this PL/SQL stored function successfully. Cant find a right way to do it..
CREATE OR REPLACE FUNCTION calGrade
(
cmark IN student.mark%TYPE
)
RETURN VARCHAR2
IS
comment VARCHAR2(10);
BEGIN
IF cmark := 1 THEN comment := 'Very Poor';
ELSIF cmark := 2 THEN comment := 'Poor';
ELSIF cmark := 3 THEN comment := 'Moderate';
ELSIF cmark := 4 THEN comment := 'Good';
ELSIF cmark := 5 THEN comment := 'Excellent';
END IF;
RETURN comment;
END;
/

Remove colon from all IFs.
SQL> CREATE OR REPLACE FUNCTION calGrade (cmark IN student.mark%TYPE)
2 RETURN VARCHAR2
3 IS
4 comment VARCHAR2 (10);
5 BEGIN
6 IF cmark = 1
7 THEN
8 comment := 'Very Poor';
9 ELSIF cmark = 2
10 THEN
11 comment := 'Poor';
12 ELSIF cmark = 3
13 THEN
14 comment := 'Moderate';
15 ELSIF cmark = 4
16 THEN
17 comment := 'Good';
18 ELSIF cmark = 5
19 THEN
20 comment := 'Excellent';
21 END IF;
22
23 RETURN comment;
24 END;
25 /
Function created.
SQL>

How about using a case expression instead?
comment := (CASE cmark
WHEN 1 THEN 'Very Poor'
WHEN 2 THEN 'Poor'
WHEN 3 THEN 'Moderate'
WHEN 4 THEN 'Good'
WHEN 5 THEN 'Excellent'
END);

Related

Generating random numbers in oracle without dbms_rand

I can't seem to use DBMSRAND.
GRANT EXECUTE ON DBMS_RANDOM TO *schema*;
ORA-01031: insufficient priveleges
Not sure why as I'm using the DBadmin schema to grant, but does anyone have a work around for random number generation in oracle sql?
If you're really desperate you could roll your own, eg here's an LG one
SQL> create or replace
2 package global is
3 a number := to_number(to_char(systimestamp,'FF'));
4 end;
5 /
Package created.
SQL>
SQL> create or replace
2 function rand(r in number) return number is
3
4 mill constant number:=100000000;
5 ten_thou constant number:=10000;
6 lg_num constant number:=31415821;
7
8 v number;
9 w number;
10 x number;
11 y number;
12 z number;
13
14 begin
15 w:=trunc(global.a/ten_thou);
16 x:=mod(global.a,ten_thou);
17 y:=trunc(lg_num/ten_thou);
18 z:=mod(lg_num,ten_thou);
19 v := mod((mod(x*y+w*z,ten_thou)*ten_thou+x*z),mill);
20 global.a:=mod(v+1,mill);
21 return(trunc((trunc(global.a/ten_thou)*r)/ten_thou));
22 end;
23 /
Function created.
SQL>
SQL> select rand(100) from dual;
RAND(100)
----------
21
SQL> select rand(100) from dual;
RAND(100)
----------
72
SQL> select rand(100) from dual;
RAND(100)
----------
1
SQL> select rand(100) from dual;
RAND(100)
----------
43
but random number generation is a science so you should be aware of the all of the limitations and drawbacks of rolling your own.
https://en.wikipedia.org/wiki/Linear_congruential_generator
So your best bet is to get appropriate access to the appropriate packages.

Why is this showing "SP2-0552: Bind variable "SEL" not declared." in sql plus?

SQL> DECLARE
2 SEL NUMBER(3);
3 ans VARCHAR(20);
4 BEGIN:
5 SEL := &SEL ;
6 CASE SEL
7 WHEN 1 THEN ans := 'SUNDAY';
8 WHEN 2 THEN ans := 'MONDAY';
9 WHEN 3 THEN ans := 'TUESDAY';
10 WHEN 4 THEN ans := 'WEDNESDAY';
11 WHEN 5 THEN ans := 'THURSDAY';
12 WHEN 6 THEN ans := 'FRIDAY';
13 WHEN 7 THEN ans := 'SATURDAY';
14
15 END CASE;
16 DBMS_OUTPUT.PUT_LINE(' CORRESPONDING DAY FOR THE NUMBER '||SEL||' IS '||DAY);
17 END;
18 /
Enter value for sel: 3
old 5: SEL := &SEL ;
new 5: SEL := 3 ;
SP2-0552: Bind variable "SEL" not declared.
There are two problems in your block:
There is a colon after BEGIN, it's not supposed to be there
In your output there is a the DAY variable that is not declared, it should be the variable ans.
Below is the working version:
DECLARE
SEL NUMBER(3);
ans VARCHAR(20);
BEGIN
SEL := &SEL ;
CASE SEL
WHEN 1 THEN ans := 'SUNDAY';
WHEN 2 THEN ans := 'MONDAY';
WHEN 3 THEN ans := 'TUESDAY';
WHEN 4 THEN ans := 'WEDNESDAY';
WHEN 5 THEN ans := 'THURSDAY';
WHEN 6 THEN ans := 'FRIDAY';
WHEN 7 THEN ans := 'SATURDAY';
END CASE;
DBMS_OUTPUT.PUT_LINE(' CORRESPONDING DAY FOR THE NUMBER '||SEL||' IS '||ans);
END;
/

Increase generation of numbers inside loop (SQL, Oracle)

I had generate 1 round numbers:
set serveroutput on
declare
i number(9);
x number(9) := 0;
begin
for i in 0..7 loop
DBMS_OUTPUT.PUT_LINE(x);
x:=x+1;
end loop;
end;
Result is: 0, 1, 2, 3....7
My next round should generate numbers: 10, 11, 12....17
Total output should looks as below:
0 1 2 3 4 5 6 7
10 11 12 13 14 15 16 17
20 21 22 23 24 25 26 27
...
80 81 82 83 84 85 86 87
How can I jump 3 between each round? I will increase my counter till 81.
set serveroutput on
declare
i number(9);
y number(9);
x number(9) := 0;
z number(9) := 0;
begin
for y in 0..8 loop
for i in 0..7 loop
DBMS_OUTPUT.PUT_LINE(x);
x := z+i+1;
end loop;
z := z + 10;
x := z;
end loop;
end;
Looks like you want to output 9 times 7 numbers. That is one loop running 9 times and inside a loop that runs 7 times, I'd say. E.g.
begin
for i in 0..8 loop
for j in 0..7 loop
dbms_output.put(i * 10 + j);
dbms_output.put(' ');
end loop;
dbms_output.put_line('');
end loop;
end;
How about such a WHILE loop?
SQL> set serveroutput on
SQL> declare
2 i number := 0;
3 begin
4 while i < 30
5 loop
6 dbms_output.put_line (i);
7
8 i := i + case when substr (to_char (i), -1) >= 7 then 3 else 1 end;
9 end loop;
10 end;
11 /
0
1
2
3
4
5
6
7
10
11
12
13
14
15
16
17
20
21
22
23
24
25
26
27
PL/SQL procedure successfully completed.
SQL>
The Logic is: if i mod 10 = 7 then increment by 3 otherwise increment by one. Thus,
set serveroutput on
declare
i number(9);
x number(9) := 0;
begin
for i in 0..100 loop
DBMS_OUTPUT.PUT_LINE(x);
IF mod(i,10) = 7 THEN
x := x +3;
ELSE
x:=x+1;
END IF;
end loop;
end;

Need SQL function for incremental sequence

Can any one provide an SQL function which input string and output the next incremental string as per the following sequence?
000000
000001
.
.
000009
00000A
.
.
00000Z
.
.
.
000010
000011
.
.
000019
00001A
.
.
zzzzzz
If you are able to use a PL/SQL function, you could try something like the function, next_step, in this block, which increments over an arbitrary numeral set.
DECLARE
i integer;
seqnum varchar2(20) := '00';
----------------------------------------
function next_step(seq_num varchar2) return varchar2 is
digits varchar2(20) := '012ABC';
last_digit varchar2(1) := substr(seq_num, length(seq_num), 1);
other_digits varchar2(20) := substr(seq_num, 1, length(seq_num) -1);
-- value of last digit
last_digit_value number(5) := instr(digits, last_digit) - 1;
BEGIN
if seq_num is null then
return substr(digits, 2, 1);
end if;
-- increment the digit; roll if needed.
last_digit_value := last_digit_value + 1;
-- "digits||digits" makes the roll easy.
last_digit := substr(digits||digits, last_digit_value + 1, 1);
if last_digit_value >= length(digits) then
-- roll over
other_digits := next_step(other_digits);
end if;
return other_digits||last_digit;
END next_step;
----------------------------------------
BEGIN
dbms_output.enable(null);
dbms_output.put_line(seqnum);
for i in 1 .. 50 loop
seqnum := next_step(seqnum);
dbms_output.put_line(' -> '||seqnum);
end loop;
END;
/
It yields the following:
00
-> 01
-> 02
-> 0A
-> 0B
-> 0C
-> 10
-> 11
-> 12
-> 1A
-> 1B
-> 1C
-> 20
-> 21
-> 22
...
-> C2
-> CA
-> CB
-> CC
-> 100
-> 101
-> 102
...
-> 121
-> 122

Convert a value based on range

I need to convert a number to another value based on a range:
ie:
7 = "A"
106 = "I"
I have a range like this:
from to return-val
1 17 A
17 35 B
35 38 C
38 56 D
56 72 E
72 88 F
88 98 G
98 104 H
104 115 I
115 120 J
120 123 K
123 129 L
129 infinity M
The values are fixed and do not change.
I was thinking a lookup table would be required, but is there a way it could be done with a function on an analytics function inside of oracle?
Think I would use a mapping table:
mapping:
to ret
17 A
38 B
Select Max(ret)
From mapping
Where x <= to
You could also use CASE WHEN:
Select Case When x <= 17 Then 'A'
When x <= 35 Then 'B'
When x <= 38 Then 'C'
...
Else 'M' End
From your_table
SQL servers are designed such that operating on a table is faster than anything else -- particularly when that table will only have 13 rows.
I would create a function, in oracle, since it should be more efficient than doing a table lookup (no roundtrip to disk will ever be involved).
CREATE OR REPLACE Function ValueFromRange
( n IN number )
RETURN varchar2
IS
ret varchar2;
BEGIN
ret := -1; -- UNDEFINED?
IF n >= 1 and n <= 17 THEN
ret := 'A';
ELSIF n >= 18 and n <= 35 THEN
ret := 'B';
ELSIF n >= 36 and n <= 38 THEN
ret := 'C';
ELSIF n >= 39 and n <= 56 THEN
ret := 'D';
ELSIF n >= 57 and n <= 72 THEN
ret := 'E';
ELSIF n >= 73 and n <= 88 THEN
ret := 'F';
ELSIF n >= 89 and n <= 98 THEN
ret := 'G';
ELSIF n >= 99 and n <= 104 THEN
ret := 'H';
ELSIF n >= 105 and n <= 115 THEN
ret := 'I';
ELSIF n >= 116 and n <= 120 THEN
ret := 'J';
ELSIF n >= 121 and n <= 123 THEN
ret := 'K';
ELSIF n >= 124 and n <= 129 THEN
ret := 'L';
ELSIF n >= 130 THEN
ret := 'M';
END IF;
RETURN ret;
END;