PLS-00201 identifier "rep_table_T" must be declared - oracle

I'm trying to compile this procedure. I whish it gets table row as parameter:
create or replace PROCEDURE MY_HELPER (rep_table_row IN OUT rep_table_T%ROWTYPE) IS
...
END MY_HELPER ;
The table is defined as
create or replace TYPE "rep_table_T" AS TABLE OF rep_table_O;
The object is defined as:
create or replace TYPE "rep_table_O" AS OBJECT (
"day" VARCHAR2(250 BYTE),
"TS" DATE
);
However I can't compile it because I'm getting the error:
PLS-00201 identifier "rep_table_T" must be declared.

Remove the %ROWTYPE. That only applies to actual sql tables, not pl/sql collections. From the documentation, "The %ROWTYPE attribute provides a record type that represents a row in a database table. "
Yeah it is very confusing as a new user that oracle calls actual tables and pl/sql tables the same thing.

Forget about double quotes while in Oracle. If you use them while creating any objects, you have to use them always.
As of your code: removed double quotes, removed rowtype in procedure declaration.
SQL> CREATE OR REPLACE TYPE rep_table_o AS OBJECT
2 (
3 day VARCHAR2 (250 BYTE),
4 ts DATE
5 );
6 /
Type created.
SQL> CREATE OR REPLACE TYPE rep_table_t AS TABLE OF rep_table_o;
2 /
Type created.
SQL> CREATE OR REPLACE PROCEDURE my_helper (
2 rep_table_row IN OUT rep_table_t)
3 IS
4 BEGIN
5 NULL;
6 END my_helper;
7 /
Procedure created.
SQL>

You have two errors:
Do not use quoted identifiers:
CREATE TYPE rep_table_O AS OBJECT (
day VARCHAR2(250 BYTE),
TS DATE
);
CREATE TYPE rep_table_T AS TABLE OF rep_table_O;
(Or, if you really must have lower-case identifiers [why?] then you need to use quoted identifiers, with exactly the same case, everywhere that identifier is used.)
Do not use %ROWTYPE:
CREATE PROCEDURE MY_HELPER (
rep_table_row IN OUT rep_table_T
)
IS
...
END MY_HELPER;
db<>fiddle here

Related

call procedure with table datatype as a Input parameter

I want to call this procedure in plsql developer.
procedure issue( ErrorCode out number,
ErrorText out varchar2,
No out number,
Date out date,
BCode in number,
BrCode in number,
ACode in varchar2,
TCode in number,
pi_docElement_InputData IN DocElement_InputData);
the last input parameter is this :
CREATE OR REPLACE TYPE "DOCELEMENT_INPUTDATA" as Table Of Prepaid_Element_Doc
and the Prepaid_Element_Doc is :
CREATE OR REPLACE TYPE "PREPAID_ELEMENT_DOC" as object(
A NUMBER(4),
B NUMBER(3),
C number(4)
)
I need to enter 2 'PREPAID_ELEMENT_DOC' as a input of procedure but I don't how to do that.
select issue(801,802,'A',1,???) from dual;
Just call the constructors for the two database types, for example
DocElement_InputData(PREPAID_ELEMENT_DOC(1,2,3),PREPAID_ELEMENT_DOC(4,5,6))
The above code creates a DocElement_InputData that contains two PREPAID_ELEMENT_DOC.
Refer to the Oracle documentation for your Oracle version.
This is for Oracle 19c
https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Type-Constructor-Expressions.html#GUID-E8A491DE-18BA-4A1E-8CE2-BBA43E5C52D6
You can call procedure with table datatype in such way
select
issue
(
801,
802,
'A',
1,
(DOCELEMENT_INPUTDATA
(
PREPAID_ELEMENT_DOC(1, 2, 3),
PREPAID_ELEMENT_DOC(3, 4, 5)
)
)
)
from
dual;

RTTI in Oracle Triggers

I have this dummy types :
create or replace type Service_TY as object(
code INTEGER,
visit_analysis char(1)
)FINAL;
/
create or replace type Employee_TY as object(
dummy varchar(30)
)NOT FINAL;
/
create or replace type Doctor_TY UNDER Employee_TY(
ID INTEGER
)FINAL;
/
create or replace type Assistant_TY UNDER Employee_TY(
ID INTEGER
)FINAL;
/
create or replace type Habilitation_TY as object(
employee ref Employee_TY,
service ref Service_TY
)FINAL;
/
And these dummy tables:
CREATE TABLE Service of Service_TY(
code primary key,
visit_analysis not null check (visit_analysis in ('v', 'a'))
);
/
CREATE TABLE Doctor of Doctor_TY(
ID primary key
);
/
CREATE TABLE Assistant of Assistant_TY(
ID primary key
);
/
CREATE TABLE Habilitation of Habilitation_TY;
/
I want to create a trigger that, when a new tuple is inserted in Habilitation, should check that, if the employee is an assistant (and not a doctor), the visit_analysis attribute is equal to 'a' to know if it is a legal tuple.
I don't know how to check the type of the Employee (if it is a doctor or an assistant).
I would do something like that:
create or replace
TRIGGER CHECK_HABILITATION
BEFORE INSERT ON HABILITATION
FOR EACH ROW
DECLARE
BEGIN
IF (:NEW.EMPLOYEE is of ASSISTANT_TY)
THEN
IF :NEW.SERVICE.visit_analysis = 'v'
THEN
raise_application_error(-10000, 'invalid tuple');
END IF;
END;
But it's not working.
How should I check that type?
The error I get is:
Error(14,4): PLS-00103: Encountered the symbol ";" when expecting one of the following: if
Try to put it into a variable, the following one should work.
create or replace
TRIGGER CHECK_HABILITATION
BEFORE INSERT ON HABILITATION
FOR EACH ROW
DECLARE
emp employee_TY;
ser service_TY;
BEGIN
select deref(:new.employee) into emp from dual;
if (emp is of (assistant_ty)) then
select deref(:new.service) into ser from dual;
if ser.visit_analysis = 'v' then
raise_application_error('-20001', 'invalid tuple');
end if;
end if;
END;
/
According to the documentation for the IS OF condition, you need to wrap the type in parentheses, like:
IF (:NEW.EMPLOYEE is of (ASSISTANT_TY) )
per https://docs.oracle.com/cd/B28359_01/server.111/b28286/conditions014.htm#SQLRF52157.
I'm not really familiar with using object types so there may be some other issue that I'm not seeing.

How can I create a table type with multiple columns and use it in a stored procedure?

I created a table type to use it as input in a stored procedure, so that the procedure can receive multiple customer IDs at once.
But now I also need to use other data related to the customers and I was wondering how I can use the type I created with multiple custom columns, and not only Customer ID.
This is how it is now:
CREATE TYPE T_CUSTOMERS IS TABLE OF NUMBER;
CREATE OR REPLACE PROCEDURE PR_SAMPLE (
CUSTOMERS_LIST IN T_CUSTOMERS,
C1 OUT SYS_REFCURSOR
)
IS
BEGIN
...
END;
You can create the OBJECT type and then create the table type containing the newly created objects.
CREATE TYPE T_CUSTOMERS_OBJ AS OBJECT (
CUSTOMER_ID NUMBER,
CUSTOMER_NAME VARCHAR2(300)
);
/
CREATE TYPE T_CUSTOMERS IS
TABLE OF T_CUSTOMERS_OBJ;
/
Then you can use the T_CUSTOMERS type in your procedure.

How can I delete a member function created in oracle

How can I delete a member function created inside oracle type object without dropping the entire type?
I never used it but according documentation you might be able to use
alter type {type_name} DROP MEMBER {function_spec} CASCADE;
Note, {function_spec} is the function name plus RETURN clause, e.g.
ALTER TYPE ttest DROP MEMBER FUNCTION f_name_2 RETURN VARCHAR2 CASCADE;
Afterwards you have to re-create the TYPE BODY without the dropped function, i.e. CREATE OR REPLACE TYPE BODY ...
As far as I can tell, you can't (unless you call CREATE OR REPLACE to be not dropping).
P.S. What's even worse, if there are dependent types that use the type with a member function you'd want to drop, you'll need to drop everything cascade. Which means that - as a function doesn't have to eat or drink - leave it alone.
[EDIT; after seeing Wernfried's answer]
It seems that I was wrong. Apparently, it really works. Syntax is somewhat strange (it requires to specify the RETURN clause (?!?)), but hey - that's what Oracle says. So, today I learnt something new.
An example:
SQL> create or replace type ttest is object
2 (some_name varchar2(20),
3 member function f_name return varchar2
4 );
5 /
Type created.
SQL> create or replace type body ttest as
2 member function f_name
3 return varchar2
4 is
5 begin
6 return self.some_name;
7 end f_name;
8 end;
9 /
Type body created.
SQL> alter type ttest drop member function f_name return varchar2;
Type altered.
SQL> desc ttest
Name Null? Type
----------------------------------------- -------- ----------------------------
SOME_NAME VARCHAR2(20)
SQL>

PLSQL using table default value in procedure default parameters while inserting

I want to create a procedure to insert values in a table. My table has default values for certain fields. I want the same defaults in my procedure without manually typing it in my procedure. eg
create table products
(
prod_id number primary key,
stock number default 0
);
My procedure declaration:
create procedure insert_product
(
prod_id number,
stock number default products.stock.default
);
But I get:
Error(58,99): PLS-00103: Encountered the symbol "DEFAULT" when
expecting one of the following: current delete exists prior The symbol " was inserted before "DEFAULT" to continue.
I tried:
stock number default );
stock number default products.stock );
But they give errors too. Can the table's default value be accessed by the procedure without typing it explicitly in the procedure ? I know
stock number default 0 ); works fine.
I am new to PLSQL so forgive me if it's a silly question.
You can you a private procedure within your main procedure and achieve this. Please check below: Please see that the code is just an example and not tested.
create or replace procedure abc
as
v_num number;
--Private Proc to Main procedure abc
Procedure insert_product ( prod_id number,
stock number )
Is
begin
<you logic>;
end;
Begin
select stock
into v_num
from products
where <condition>;
insert_product(PROD_ID,v_num);
End ;

Resources