PL/SQL: I don't know how to properly insert data into a nested table of type object of 2 columns. Error:"Not enough values" - plsql

My code:
create or replace type imb_rec is object(cod number, job varchar2(20));
create or replace type tab_imbr is table of imb_rec;
alter table dept_ast add info tab_imbr;
declare
v_imb tab_imbr := tab_imbr();
i number:=10;
v_rec imb_rec;
begin
while i<=270 loop
v_imb.extend;
select employee_id, job_id bulk collect into v_imb
from emp_ast
where department_id=i;
update dept_ast
set info=v_imb
where department_id=i;
delete v_imb;
i:=i+10;
end loop;
for i in 1..dept_ast.count loop
dbms_output.put_line('Codul departmentului: '||dept_ast(i).department_id);
dbms_output.put_line('Angajatii: '||dept_ast(i).department_id);
for j in 1..dept_ast(i).info.count loop
dbms_output.put_line('Codul ang: '||dept_ast(i).info(j).cod||', job: '||dept_ast(i).info(j).job);
end loop;
end loop;
end;
/
I also have the error "must specify table name for nested table column or attribute" when I try to alter my dept_ast table by adding a new column of type nested table. I get the error "Not enough values" when I try to perform the select. I want to select, for each department (department_id increases by 10 each time) the employee id and job id for each employee for that department, and save those values in a variable of type nested table, save this table in my dept_ast table that has a column of this specific type, delete the values from the nested table so that I can save new values at the next iteration, the repeat. I don't know if my method is any good.
Error report:
ORA-06550: line 10, column 52:
PL/SQL: ORA-00947: not enough values
ORA-06550: line 10, column 1:
PL/SQL: SQL Statement ignored
ORA-06550: line 15, column 5:
PL/SQL: ORA-00904: "INFO": invalid identifier
ORA-06550: line 14, column 1:
PL/SQL: SQL Statement ignored
ORA-06550: line 18, column 8:
PL/SQL: ORA-00942: table or view does not exist
ORA-06550: line 18, column 1:
PL/SQL: SQL Statement ignored
ORA-06550: line 23, column 22:
PLS-00302: component 'COUNT' must be declared
ORA-06550: line 23, column 1:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
My dept_ast table has the columns:
DEPARTMENT_ID NUMBER(4,0)
DEPARTMENT_NAME VARCHAR2(30 BYTE)
MANAGER_ID NUMBER(6,0)
LOCATION_ID NUMBER(4,0)
And I want to add a new column to dept_ast of type nested table of object, and the object has 2 columns:
EMPLOYEE_ID NUMBER(6,0)
JOB_ID VARCHAR2(10 BYTE)
Basically, I want to have in my dept_ast table a new column that will be the collection of the employees that work in that specific department. Every line in dept_ast is information about a department.

I corrected the code by myself:
create or replace type imb_rec is object(cod number, job varchar2(20));
create or replace type tab_imbr is table of imb_rec;
alter table dept_ast add info tab_imbr nested table info store as info_t;
rollback;
set serveroutput on
select *
from dept_ast;
declare
v_imb tab_imbr := tab_imbr();
i number:=10;
v_rec imb_rec;
type code_dep is table of dept_ast.department_id%type;
code_dep_t code_dep:=code_dep();
begin
select department_id
bulk collect into code_dep_t
from dept_ast;
while i<=270 loop
v_imb.extend;
from emp_ast
where department_id=i;
update dept_ast
set info=v_imb
where department_id=i;
v_imb.delete;
i:=i+10;
end loop;
for i in 1..code_dep_t.count loop
dbms_output.put_line('Codul departmentului: '||code_dep_t(i));
select imb_rec(employee_id, job_id)
bulk collect into v_imb
from emp_ast
where department_id=code_dep_t(i);
for j in 1..v_imb.count loop
dbms_output.put_line('Codul ang: '||v_imb(j).cod||', job: '||v_imb(j).job);
end loop;
v_imb.delete;
end loop;
end;
/
I can't just type select employee_id, job_id bulk collect into v_imb, because v_imb is nested table of type object of 2 columns, so I need a constructor for the 2 columns:
select imb_rec(employee_id, job_id) bulk collect into v_imb. Also I can't write
for i in 1..dept_ast.count loop, because dept_ast is just a table, not a nested table, so I need to select the values and save them in a collection before outputting them.

Related

Expression is of wrong type when sending nested array to Function

I want to send a collection to a Function, but I keep getting an error.
I defined the RECORD and TYPES in my Package Header and Implemented the body aswell. I dont understand why I cant send a simple collection as a parameter, the idea is for me to loop through the collection and do some comparisation then return a char within a sql statement.
Been struggling with this for a week now, any help is appreciated.
Exact error:
ORA-06550: line 9, column 45:
PLS-00382: expression is of wrong type
ORA-06550: line 9, column 40:
PLS-00306: wrong number or types of arguments in call to 'TEST_F'
ORA-06550: line 9, column 23:
PL/SQL: ORA-00904: "PACKAGE_SS"."TEST_F": invalid identifier
ORA-06550: line 9, column 3:
PL/SQL: SQL Statement ignored
Header:
create or replace
PACKAGE PACKAGE_SS AS
type t_itemnumber is table of varchar2(100) index by BINARY_INTEGER;
type t_alternative_rec is record
(
itemnumber t_itemnumber
);
type t_alternative_prev is table of t_alternative_rec INDEX BY BINARY_INTEGER;
type t_procestype_rec is record
(
procestype char
);
TYPE result_table IS TABLE OF t_procestype_rec;
FUNCTION test_f(p_items_prev IN t_alternative_prev) RETURN result_table PIPELINED;
END AOPA_VALIDATE_SS;
The package body looks like this:
create or replace
PACKAGE BODY PACKAGE_SS AS
FUNCTION test_f(p_items_prev IN t_alternative_prev) RETURN result_table PIPELINED IS
processType char(1) := 'U';
rec t_procestype_rec :=null;
BEGIN
DBMS_OUTPUT.PUT_LINE('ENTERD ');
if (processType= 'U') then
select 'U' into rec from dual;
end if;
if (processType='C') then
select 'C' into rec from dual;
end if;
if (processType='D') then
select 'D' into rec from dual;
end if;
pipe row (rec);
return;
END test_f;
END PACKAGE_SS;
Usage plsql script:
DECLARE
prev_rev_alternatives PACKAGE_SS.t_alternative_prev;
BEGIN
prev_rev_alternatives(1).itemnumber(10) := 'PR454545';
prev_rev_alternatives(1).itemnumber(20) := 'PR333333';
SELECT * FROM table(PACKAGE_SS.test_f(prev_rev_alternatives));
END;
There are two things which my eyes fall upon:
Usage of SELECT without INTO in an anonymous PLSQL block is not supposed to work.
Usage of types in an SQL statement requires the type defined as an object, not within a package specification.
Try
CREATE TYPE
https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_8001.htm
and
SELECT * INTO ... FROM ...
This might help.

Getting error while assigning values to records inside collection

I need to loop through some values inside the plsql code.
so trying to create a collection of records .
getting error as mentioned below.
Please help me to resolve
-- please see the code below
declare
type tab_name is record (t_name varchar2(30),col_name varchar2(30));
type tab_list is table of tab_name;
table_names tab_list:=tab_list(tab_name('ABC','abc'),tab_name('XYZ','xyz'));
begin
for i in table_names.first..table_names.last loop
dbms_output.put_line(table_names(i).t_name||'-'||table_names(i).col_name);
end loop;
end;
/
Error report -
ORA-06550: line 4, column 32:
PLS-00222: no function with name 'TAB_NAME' exists in this scope
ORA-06550: line 4, column 13:
PL/SQL: Item ignored
ORA-06550: line 6, column 10:
PLS-00320: the declaration of the type of this expression is incomplete or malformed
ORA-06550: line 6, column 1:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
Record type's name is not its initializer.
In fact, there is no initialization-like function for record types at all in oracle:
Documentation
Note that values are assigned separately to each field of a record in
Example 5-47. You cannot assign a list of values to a record using an
assignment statement. There is no constructor-like notation for
records.
You have to create each object separately and then create collection with them:
declare
type tab_name is record (t_name varchar2(30),col_name varchar2(30));
type tab_list is table of tab_name;
name_1 tab_name;
table_names tab_list;
begin
name_1.t_name := 'ABC';
name_1.col_name := 'abc';
table_names := tab_list();
table_names.extend;
table_names(table_names.last) := name_1;
name_1.t_name := 'XYZ';
name_1.col_name := 'xyz';
table_names.extend;
table_names(table_names.last) := name_1;
for i in table_names.first..table_names.last
loop
dbms_output.put_line(table_names(i).t_name||'-'||table_names(i).col_name);
end loop;
end;
Collections DO have initializers. However, in your case you have a collection of record types, so you would have to have your records pre-created to make use of it.

PLSQL script not working with passing multiple values into IN() caluse

I am very new in PLSQL, i want to pass an array of number into IN() clause value, But Sqldeveloper throw following error messages:
Error report -
ORA-06550: line 11, column 60:
PLS-00382: expression is of wrong type
ORA-06550: line 11, column 53:
PL/SQL: ORA-22905: cannot access rows from a non-nested table item
ORA-06550: line 10, column 4:
PL/SQL: SQL Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
This is my code :
DECLARE
TYPE sc IS TABLE OF transactionhistory.NBSUBCOMPANY%TYPE INDEX BY PLS_INTEGER;
arr sc;
BEGIN
arr(0) := 000;
arr(1) := 111;
arr(2) := 222;
arr(3) := 333;
select count(th.CHCARDNUMBER) as transactions from transactionhistory th INNER JOIN cards ch on ch.NBATTMID=th.NBATTMID where th.dtdate>=to_date('01-oct-2016','dd-mon-yyyy') and th.dtdate<to_date('01-nov-2016','dd-mon-yyyy')
and ch.NBSUBCOMPANY IN (select column_value from table (arr))
and ((th.CHTRANSTYPE in ('2940', '2916', '2941', '2942', '2943', '2944', '2945', '2902', '2917', '2925') and th.NBBASEAMT < 0) or (th.CHTRANSTYPE in ('2922', '2923', '2926', '2950', '2951', '2952', '2953', '2954', '2955') and th.NBBASEAMT > 0) or (th.CHTRANSTYPE in ('1101', '1102', '1104', '1105', '1106', '1107', '1109') and th.BASEII_STATUS = 'C') or th.CHTRANSTYPE not in ('2940', '2916', '2941', '2942', '2943', '2944', '2945', '2902', '2917', '2925', '2922', '2923', '2926', '2950', '2951', '2952', '2953', '2954', '2955', '1101', '1102', '1104', '1105', '1106', '1107', '1109'));
END;
Please suggest me how can i pass this.
You will need to have a workaround.
SQL doesn't support local collection types to be used in the way you want.
Sample Procedure below which will help in resolving
CREATE OR REPLACE type TEST_TYPE
IS
TABLE OF NUMBER;
You will need to create a type in the database for this to work. Can be created inside a package, if you have one.
DECLARE
TEST_VAR TEST_TYPE := TEST_TYPE();
BEGIN
TEST_VAR.extend(1);
TEST_VAR(TEST_VAR.last) := 222;
TEST_VAR.extend(1);
TEST_VAR(TEST_VAR.last) := 333;
FOR rec IN
(SELECT column_value
FROM TABLE(TEST_VAR)
)
LOOP
dbms_output.put_line(rec.column_value);
END LOOP;
END;
Output
222
333
This way, you can use select column_value from table(test_var) for your IN() clause.
Also, you don't necessarily need to follow the extend(i) part. you can simply do the below as well
TEST_VAR TEST_TYPE := TEST_TYPE(222,333);
Have a read - local collection types not allowed in SQL statements
You can use MEMBER OF clause. See below:
As #Sudipta mentioned you cannot use a collection decalred in PLSQL block as you are doing, you need to declare it outside of the PLSQL block.
CREATE OR REPLACE TYPE sc IS TABLE OF NUMBER;
and then
DECLARE
-- TYPE sc IS TABLE OF NUMBER INDEX BY PLS_INTEGER;
arr sc:=sc();
num number;
BEGIN
arr.extend(4);
arr(1) := 0;
arr(2) := 1;
arr(3) := 2;
arr(4) := 3;
Select count(1)
into num
from employee
-- You can use either commented one or uncommented one. your choice.
--where employee_id in (select column_value from table(arr));
where employee_id member of arr;
END;

Invalid identifier while updating a column using cursor for loop?

I am trying to update salary column in my table using cursors.
This is my code:
declare
cursor c1 is
select * from emp2_1030082;
begin
for c3 in c1
loop
if(c3.salary>10000)
then
update emp2_1030082 set c3.salary=c3.salary + c3.salary/10 ;
elsif(c3.salary<=10000)
then
update emp2_1030082 set c3.salary= c3.salary + c3.salary/20 ;
end if;
end loop;
end;
But I'm getting this error:
ORA-06550: line 9, column 47:
PL/SQL: ORA-00904: "C3"."SALARY": invalid identifier
ORA-06550: line 9, column 1:
PL/SQL: SQL Statement ignored
ORA-06550: line 12, column 25:
PL/SQL: ORA-00904: "C3"."SALARY": invalid identifier
ORA-06550: line 12, column 1:
PL/SQL: SQL Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
The first question is, do you really need to do this in a cursor? Because executing these two statements should do what you want:
update emp2_1030082 set salary=salary + salary/10 where salary > 10000;
update emp2_1030082 set salary=salary + salary/20 where salary <= 10000;
Meanwhile, the error you are getting is because in
update emp2_1030082 set c3.salary=c3.salary + c3.salary/10 ;
By using the c3. in set c3.salary you are referring to the cursor instead of the column name in the table that you want to update. Just salary (and in the other update as well) should make the error go away, BUT, you will update all rows with every update, so pretty sure that's not what you want.
To do it with a cursor, you should remove the the c3. from where it doesn't belong, and then add a where clause to update only the current record. Hopefully you have some kind of unique ID, and then it would be something like:
update emp2_1030082 set salary=c3.salary + c3.salary/10 where id = c3.id;

create procedure keyword won't work

if i write procedure creating code like this
declare
salary number :=20000;
employee_id number :=36325;
procedure give_bonus(emp_id in number,bonus in number) is
begin
dbms_output.put_line(emp_id);
dbms_output.put_line(bonus);
end;
begin
case
when salary >=10000 and salary <=20000 then
give_bonus(employee_id,1500);
when salary >= 20000 and salary <=40000 then
give_bonus(employee_id,1000);
when salary>40000 then
give_bonus(employee_id,500);
else
give_bonus(employee_id,0);
end case ;
end;
it writes on output
anonymous block completed
but if i write a head of procedure word this one
create or replace procedure give_bonus ,it writes errors,please help me why?
error is this
Error starting at line 1 in command:
declare
salary number :=20000;
employee_id number :=36325;
create or replace procedure give_bonus(emp_id in number,bonus in number) is
begin
dbms_output.put_line(emp_id);
dbms_output.put_line(bonus);
end;
begin
case
when salary >=10000 and salary <=20000 then
give_bonus(employee_id,1500);
when salary >= 20000 and salary <=40000 then
give_bonus(employee_id,1000);
when salary>40000 then
give_bonus(employee_id,500);
else
give_bonus(employee_id,0);
end case ;
end;
Error report:
ORA-06550: line 4, column 3:
PLS-00103: Encountered the symbol "CREATE" when expecting one of the following:
begin function pragma procedure subtype type <an identifier>
<a double-quoted delimited-identifier> current cursor delete
exists prior
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
CREATE OR REPLACE only works for top-level objects. If you are declaring a procedure inside of another PL/SQL block, there is, by definition, nothing to replace. You aren't creating a procedure that will exist once the anonymous block finishes so there is nothing to replace. You're simply declaring a procedure that has the same scope as a local variable.
You could create a standalone procedure
create or replace procedure give_bonus(emp_id in number,bonus in number)
is
begin
dbms_output.put_line(emp_id);
dbms_output.put_line(bonus);
end;
and then reference that procedure in your anonymous PL/SQL block
declare
salary number :=20000;
employee_id number :=36325;
begin
case
when salary >=10000 and salary <=20000 then
give_bonus(employee_id,1500);
when salary >= 20000 and salary <=40000 then
give_bonus(employee_id,1000);
when salary>40000 then
give_bonus(employee_id,500);
else
give_bonus(employee_id,0);
end case ;
end;

Resources