create or replace function cart_jaune(code in equipe.num_eq%type) return integer as
nb integer := 0;
begin
select count(*)
into nb
from sanctionner s, joueur j
where s.code_joueur = j.code_joueur
and j.num_eq = code
and s.type_catron like '%jaune%';
return nb;
end;
/
Depending on tool you use, you should check which error you got. Because, how is anyone supposed to assist? What works regardless of a tool is querying user_errors. For example:
SQL> create or replace function f_test return number is
2 begin
3 retval := 1; --> variable isn't declared, so - compilation will fail
4 return retval;
5 end;
6 /
Warning: Function created with compilation errors.
SQL> select line, position, text from user_errors where name = 'F_TEST' order by line, position;
LINE POSITION TEXT
----- --------- --------------------------------------------------
3 3 PLS-00201: identifier 'RETVAL' must be declared
3 3 PL/SQL: Statement ignored
4 3 PL/SQL: Statement ignored
4 10 PLS-00201: identifier 'RETVAL' must be declared
Or, in SQL*Plus:
SQL> show err
Errors for FUNCTION F_TEST:
LINE/COL ERROR
-------- -----------------------------------------------------------------
3/3 PL/SQL: Statement ignored
3/3 PLS-00201: identifier 'RETVAL' must be declared
4/3 PL/SQL: Statement ignored
4/10 PLS-00201: identifier 'RETVAL' must be declared
SQL>
So, sooner you tell us what's wrong, sooner we'll be able to help.
Meanwhile, I created sample tables you used in your function. Everything seems to be OK.
SQL> create table equipe(num_eq number);
Table created.
SQL> create table sanctionner (code_joueur number, type_catron varchar2(10));
Table created.
SQL> create table joueur (code_joueur number, num_eq number);
Table created.
Function: I didn't change anything, just formatted it a little bit:
SQL> create or replace function cart_jaune(code in equipe.num_eq%type)
2 return integer
3 as
4 nb integer := 0;
5 begin
6 select count(*)
7 into nb
8 from sanctionner s,
9 joueur j
10 where s.code_joueur = j.code_joueur
11 and j.num_eq = code
12 and s.type_catron like '%jaune%';
13
14 return nb;
15 end;
16 /
Function created.
Does it work?
SQL> select cart_jaune(1) from dual;
CART_JAUNE(1)
-------------
0
SQL>
Yes, it works.
You pass the code value with the type EQUIPE.NUM_EQ%TYPE but compare it to the JOUEUR.NUM_EQ column. Unless you have two tables with the columns with the same name and data type then you probably wanted to declare the type in the signature to be JOUEUR.NUM_EQ%TYPE:
create or replace function cart_jaune(code in joueur.num_eq%type) return integer as
nb integer := 0;
begin
select count(*)
into nb
from sanctionner s, joueur j
where s.code_joueur = j.code_joueur
and j.num_eq = code
and s.type_catron like '%jaune%';
return nb;
end;
/
db<>fiddle here
AS others said, you need to show the error. We shouldn't have to play a game of "Guess What's In My Pocket?"
That said, ansi JOIN syntax has been available for, what, 20 years? You should use it:
select count(*)
into nb
from sanctionner s,
join joueur j on s.code_joueur = j.code_joueur
where j.num_eq = code
and s.type_catron like '%jaune%';
Helps insure you account for all of the joins.
Since we're playing "guess my error message", here's mine:
In your SQL query, you refer to code:
and j.num_eq = code
Since you have not provided any alias for code, the SQL engine will first try to match it to a column in any of the tables listed in your FROM clause.
If, for example, sanctionner has a column code, that will be what the SQL engine will use here, i.e.:
select count(*)
into nb
from sanctionner s, joueur j
where s.code_joueur = j.code_joueur
and j.num_eq = s.code
and s.type_catron like '%jaune%';
Since you actually wanted it to bind your PL/SQL function parameter, you need to provide the alias, i.e.:
select count(*)
into nb
from sanctionner s, joueur j
where s.code_joueur = j.code_joueur
and j.num_eq = cart_jaune.code
and s.type_catron like '%jaune%';
In fact, it's best practice to always provide aliases for all columns and binds, especially when embedding SQL within PL/SQL.
Related
CREATE OR REPLACE TYPE a IS OBJECT
(
b integer,
c varchar2(10)
);
/
declare
cursor ca return a is select 1,'e' from dual;
va a;
begin
null;
for cur in ca
loop
DBMS_OUTPUT.PUT_LINE('do nothing');
end loop;
end;
ORA-03113: end-of-file on communication channel
Process ID: 803778
Session ID: 64 Serial number: 4181
the loop as only one element and fast nothing is done in the loop.
But I get the error end-of-file communication channel
As #littlefoot said it works fine if I use a record defined in a package or no record at all. I don't know why it doesn't work with an object
code
Simply put, you can't do that.
Oracle does not support returning object types from a cursor. Cursors *always* return a rowtype. So to do something similar to what you want, you can define a table which has a column of the object type you're interested in, and then have the cursor return the rowtype of that table - i.e. something like:
CREATE OR REPLACE TYPE a IS OBJECT
(
b integer,
c varchar2(10)
);
CREATE TABLE tt
(t_a a);
INSERT INTO tt VALUES (a(1, 'e'));
declare
cursor ca return tt%ROWTYPE is select t_a from tt;
an_a a;
begin
FOR aRow IN ca LOOP
an_a := aRow.t_a;
dbms_output.put_line('an_a.b=' || an_a.b);
dbms_output.put_line('an_a.c=''' || an_a.c || '''');
end loop;
end;
db<>fiddle here
You never said what a is.
Documentation says that - if you use return clause, then it returns rowtype.
RETURN: Specifies the datatype of a cursor return value. You can use the %ROWTYPE attribute in the RETURN clause to provide a record type that represents a row in a database table or a row returned by a previously declared cursor. Also, you can use the %TYPE attribute to provide the datatype of a previously declared record.
A cursor body must have a SELECT statement and the same RETURN clause as its corresponding cursor spec. Also, the number, order, and datatypes of select items in the SELECT clause must match the RETURN clause.
ROWTYPE: A record type that represents a row in a database table or a row fetched from a previously declared cursor or cursor variable. Fields in the record and corresponding columns in the row have the same names and datatypes.
So, if your code were like this, it would work:
SQL> set serveroutput on
SQL>
SQL> declare
2 type a is record(val1 number, val2 varchar2(10));
3
4 cursor ca return a is select 1 ,'e' from dual;
5 va a;
6 begin
7 for cur in ca
8 loop
9 DBMS_OUTPUT.PUT_LINE(cur.val1 ||', '|| cur.val2 ||', do nothing');
10 end loop;
11 end;
12 /
1, e, do nothing
PL/SQL procedure successfully completed.
SQL>
Or, simpler, if you remove the return clause from your own code, it would also work:
SQL> declare
2 cursor ca --return a
3 is select 1,'e' from dual;
4 va a;
5 begin
6 null;
7 for cur in ca
8 loop
9 DBMS_OUTPUT.PUT_LINE('do nothing');
10 end loop;
11 end;
12 /
do nothing
PL/SQL procedure successfully completed.
SQL>
If you're asking what's the reason of end-of-file on communication channel, I wouldn't know.
I didn't find a way to do that.
https://dbfiddle.uk/?rdbms=oracle_21&fiddle=d17c9f9a15fd32367c2fad58d48ac04c
CREATE TYPE arguments_r IS OBJECT
(
q integer,
b INTEGER
);
CREATE OR REPLACE FUNCTION f (p IN arguments_r)
RETURN INTEGER
IS
BEGIN
RETURN 1;
END;
with a(a1,a2) as (select 1 , 2 from dual)
select f(arguments_r(a.* )) from a;
ORA-01747: invalid user.table.column, table.column, or column specification
I could select the name of all column (like what propose Connor McDonald) but I don't want to do that.
I've a table (my_table) with a lot a columns and I will use a lot of this columns in my function. The type of the argument of my function is my_table%ROWTYPE.
You're close - you just to pass the object from the query columns
SQL> CREATE TYPE arguments_r IS OBJECT
2 (
3 q integer,
4 b INTEGER
5 );
6 /
Type created.
SQL>
SQL> CREATE OR REPLACE FUNCTION f (p IN arguments_r)
2 RETURN INTEGER
3 IS
4 BEGIN
5 RETURN 1;
6 END;
7 /
Function created.
SQL> with a as
2 (select 1 x, 2 y from dual)
3 select f(arguments_r(x,y)) from a;
F(ARGUMENTS_R(X,Y))
-------------------
1
this is my code for procedure. i have created two tables as Stud_Marks and Result with some data in it...and then i have created this procedure. at run time it shows error for "object SYS.FIND_CLASS is invalid".
SQL> create or replace procedure find_class(roll IN number) IS
2 tm number (10);
3 begin
4 select total_marks into tm from stud_marks where name IN(select name from result where roll=roll_no);
5 if(tm<=1500 and tm>=990)then
6 update result set class='distin' where roll_no=roll;
7 elseif(tm>900 and tm<989)then
8 update result set class='first' where roll_no=roll;
9 elseif(tm<=899 and tm>=825)then
10 update result set class='second' where roll_no=roll;
11 end if;
12 exception when no_data_found then
13 dbms_output.put_line('roll no is not matched with the entry');
14 end;
15 /
[enter image description here][1]
Warning: Procedure created with compilation errors
.
SQL> declare
2 r number(10);
3 begin
4 r:=&roll_no;
5 find_class(r);
6 end;
7 /
Enter value for roll_no: 1
old 4: r:=&roll_no;
new 4: r:=1;
find_class(r);
*
ERROR at line 5:
ORA-06550: line 5, column 1:
PLS-00905: object SYS.FIND_CLASS is invalid
ORA-06550: line 5, column 1:
PL/SQL: Statement ignored
then i am getting an error for find_class(r)..why???
Before calling the procedure, you must make sure it is valid. Yours isn't so Oracle raises an error.
Once you created it, you got a message saying
Warning: Procedure created with compilation errors
You should have checked what's wrong by running command
show err
I reformatted code you posted - see how it is easier to read:
create or replace procedure find_class(roll IN number) IS
tm number (10);
begin
select total_marks
into tm
from stud_marks
where name IN (select name
from result
where roll = roll_no
);
if (tm <= 1500 and tm >= 990)then
update result set
class = 'distin'
where roll_no = roll;
elsif (tm > 900 and tm < 989) then --> ELSIF, not ELSEIF
update result set
class = 'first'
where roll_no = roll;
elsif (tm <= 899 and tm >= 825) then --> ELSIF, not ELSEIF
update result set
class = 'second'
where roll_no = roll;
end if;
exception when no_data_found then
dbms_output.put_line('roll no is not matched with the entry');
end;
Apparently, you used ELSEIF while it should be ELSIF. I don't know whether that's the only error as I don't have your tables - you'll find that out. Don't forget to show err if necessary!
So, once it is created without errors, you can call it and see what it does.
P.S. Forgot to mention: why do you do it connected as SYS? That user owns the database and should not be used for development or educational purposes. You should use one of predefined users (such as Scott or HR) or create your own user. Leave SYS alone.
There are two tables
Customer2(CUSTID,NAME,ADDRESS,AGE,SALARY)
Order2(ORDERID, ORDERNAME,PRICE,CUSTID)
the main issue is to find total no of order made by the customer from the location
this is the plsql function of I wrote:
CREATE OR REPLACE FUNCTION totalCustomer (loc IN VARCHAR2) RETURN NUMBER IS
total number(2) := 0;
add CHAR := loc;
BEGIN
SELECT COUNT(*) FROM order2 WHERE cusid IN (SELECT cusid FROM customer2 WHERE address='add');
RETURN total;
END;
/
and this is where I'm calling the function:
DECLARE
p VARCHAR2(100);
BEGIN
p:= &p;
dbms_output.put_line (totalCustomer (p));
END;
/
I'm getting this error Warning: Function created with compilation errors.
and this one while I'm calling the function
ERROR at line 5:
ORA-06550: line 5, column 23:
PLS-00905: object SYSTEM.TOTALCUSTOMER is invalid
ORA-06550: line 5, column 1:
PL/SQL: Statement ignored
In your function:
You wrote cusid in your query but the columns are named custid in the tables.
You don't put the query result in the variable total. Your function will always return 0 the initial value you set for total.
By writing 'add' you compared the address to the literal string "add" rather than the contents of the variable add.
But there's no need to copy loc to add. You can use loc directly.
The type of number(2) for total seems a little small. Better go with number(38) (integer) instead.
The query is better written with an inner join. IN with a subquery often does not perform well.
Instead of being char the type of loc should be the type of address in customer2. You can use customer2.address%TYPE here.
CREATE OR REPLACE FUNCTION totalcustomer (loc IN customer2.address%TYPE)
RETURN number
IS
total number(38) := 0;
BEGIN
SELECT count(*) INTO total
FROM order2 o
INNER JOIN customer2 c
ON c.custid = o.custid
WHERE address = loc;
RETURN total;
END;
/
And in your anonymous block:
You declared p as char which means char(1), i.e. p can only hold one character. I'm not sure this is what you want. You can go with customer2.address%TYPE here too.
DECLARE
p customer2.address%TYPE;
BEGIN
p := &p;
dbms_output.put_line(totalcustomer(p));
END;
/
When I compile the below code I am getting a error message "Function created with compilation errors"
create or replace function find_port(ip_ID in int) RETURN int
is
t_count number;
count varchar;
begin
select is_rail into count from table where id = ip_ID;
case
when count ='True' then t_count:=1;
when count ='False' then t_count:=0;
end case;
end;
/
i am getting a error message "Function created with compilation errors"
So the question you should be asking is, "how do I get a list of compilation errors for my PL/SQL code?"
Other people have told you how to fix the current errors in your code, but the more important skill is that you find out how to diagnose your code for yourself.
Oracle is a database, and it stores metadata in a set of special views called the data dictionary. These views include views for compilation errors. This query will work in any SQL environments:
select name, type, line, text -- or just *, obvs
from user_errors ue
order by ue.name, ue.type, ue.sequence;
There are also ALL_ERRORS and DBA_ERRORS views. Find out more.
In SQL*Plus you can run sho err (short for show errors). IDEs like PL/SQL Developer or Oracle SQL Developer will show compilation errors automatically.
Once you know how to get the text of the errors you need to know that LINE will tell you the line where the error is raised. Although with certain classes of error (such as missing commas or unmatched brackets) the indicated line may not be the line where the actual error resides. Unfortunately there is still a need for interpretation and understanding, which requires experience.
Actually, COUNT can be used as a PL/SQL variable:
SQL> create or replace function f_test return int is
2 count number;
3 begin
4 select 1 into count from dual;
5 return 2;
6 end;
7 /
Function created.
SQL> select f_test from dual;
F_TEST
----------
2
SQL>
However, you can't return it:
SQL> create or replace function f_test return int is
2 count number;
3 begin
4 select 1 into count from dual;
5 return count;
6 end;
7 /
Warning: Function created with compilation errors.
SQL> show err
Errors for FUNCTION F_TEST:
LINE/COL ERROR
-------- -----------------------------------------------------------------
5/3 PL/SQL: Statement ignored
5/10 PLS-00204: function or pseudo-column 'COUNT' may be used inside a
SQL statement only
SQL>
Here, #priya, you can see how to help yourself - SHOW ERR will tell you what's wrong with your code.
Apart from that, CASE statement you used was invalidly written; should have been similar to this:
SQL> create or replace function f_test return int is
2 l_count number;
3 t_count number;
4 begin
5 select 1 into l_count from dual;
6
7 t_count := case when l_count = 1 then 1
8 when l_count = 2 then 2
9 end;
10
11 return t_count;
12 end;
13 /
Function created.
SQL> select f_test from dual;
F_TEST
----------
1
SQL>
count is a SQL function and thus not a better choice to be used as a PL/SQL variable. The CASE block can be used within the select statement.
Furthermore, your function does not RETURN any value.
create or replace function find_port(ip_ID in int) RETURN int
is
t_count number;
begin
select case
when is_rail = 'True' then 1
when is_rail = 'False' then 0
end into t_count from yourtable where id=ip_ID;
RETURN t_count;
end;