using plsql table in a procedure - oracle

I am using plsql in a oracle database 9i
I have a stored procedure,
With an in parameter of "table of number" that is called numbers.
I now want to select all rows from a table where a column named: ID is equal to a number inside "numbers"
Just like I can do select * from table name where Id in (!,!,!,...)
Thanks for the help.
Update :
Just to clear up,
I have a user defined type named numbers,
Number is defined: table of number.
So in the procedure decleration I have
"P_array in numbers"
I need to select * from a table where Id is found in p_array

like this?
SQL> create type numbers as table of number;
2 /
Type created.
SQL> create table foo (id number) ;
Table created.
SQL> insert into foo select rownum from dual connect by level <= 10;
10 rows created.
SQL> select * from foo;
ID
----------
1
2
3
4
5
6
7
8
9
10
10 rows selected.
SQL> create procedure testnum(p_num in numbers)
2 is
3 begin
4 for r_row in (select id
5 from foo f
6 where f.id in (select /*+ cardinality(t, 10) */ column_value
7 from table(p_num) t))
8 loop
9 dbms_output.put_line(r_row.id);
10 end loop;
11 end;
12 /
Procedure created.
SQL> set serverout on
SQL> exec testnum(numbers(2, 6, 9));
2
6
9
the cardinality hint is used to tell oracle roughly how many elements are in your table. without it, Oracle will assume ~8k rows which may be too high and cause unwanted full scans in the plans.
you can do a direct join too if you prefer.
for r_row in (select /*+ cardinality(t, 10) */ f.id
from foo f
inner join table(p_num) t
on t.column_value = f.id)

try the following :-
select * from tableName where id in (select c.column_value from table(cast(p_array as numbers)) c);
where numbers is table of number

SELECT * FROM A_TABLE WHERE ID IN (SELECT SAVED_NUMBERs FROM TABLE_NUMBER);
Do you mean this?

Related

Update second column

I have a table "TEST_TABLE" with two columns TABLE_NAME and RECORD_COUNT.
enter image description here
We want to update the column RECORD_COUNT by taking the total records in table specified in TABLE_NAME.
You could do this with dynamic SQL but why be complicated?
Create a view
Create view my_tables as
Select
'table_1' as "table name",
count(*) as "rows"
From table_1
Add the following for each table
Union all
Select 'table_2',count(*) From table_2
You can then use the view like a table:
Select * from my_tables;
OK, but - why wouldn't you use information Oracle already provides for you? You should regularly gather statistics anyway, so:
SQL> execute dbms_stats.gather_schema_stats(ownname => 'SCOTT', estimate_percent => null);
PL/SQL procedure successfully completed.
and then fetch num_rows from user_tables:
SQL> select table_name, num_rows from user_tables where rownum <= 10;
TABLE_NAME NUM_ROWS
-------------------- ----------
EMP 14
DEPT 4
BONUS 0
SALGRADE 5
DUMMY 1
TBL_ERROR 1
AUDIT_TAB 2
SOURCE_DET 3
EXAMPLE 1
FLIGHT 0
10 rows selected.
SQL>
It can't be much worse than your attempt (due to possible frequent changes to tables' contents; inserts and deletes) because you'd collect your own data periodically (how often?) anyway.
If it has to be your way, then you'd use dynamic SQL, looping through all tables in your schema and actually count number of rows:
SQL> create table test_table
2 (table_name varchar2(30),
3 num_rows number);
Table created.
SQL> create or replace procedure p_test as
2 l_cnt number;
3 begin
4 execute immediate 'truncate table test_table';
5 for cur_R in (select table_name from user_tables) loop
6 execute immediate 'select count(*) from ' ||cur_R.table_name into l_Cnt;
7 insert into test_table (table_name, num_rows) values (cur_r.table_name, l_cnt);
8 end loop;
9 end;
10 /
Procedure created.
Running the procedure and viewing the result:
SQL> exec p_test;
PL/SQL procedure successfully completed.
SQL> select * From test_Table where rownum <= 10;
TABLE_NAME NUM_ROWS
-------------------- ----------
EMP 14
DEPT 4
BONUS 0
SALGRADE 5
DUMMY 1
TBL_ERROR 1
AUDIT_TAB 2
SOURCE_DET 3
EXAMPLE 1
FLIGHT 0
10 rows selected.
SQL>
Note that performance will suffer as number of tables and number of rows stored in them grows.
If I were you, I'd go for the first option.

How to duplicate records with triggers?

CREATE OR REPLACE TRIGGER "DUPLICATE_FOO" AFTER INSERT ON "FOO" FOR EACH ROW
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
insert into remote_foo values(:new); -- can I do this?
EXCEPTION
-- TODO log somewhere
END;
Is there an elegant way to create a trigger that basically duplicates a record from one table to another?
I would like to avoid having to specify the fields of the table since it will mean that the trigger would have to be updated in case there are changes in the schema (the remote scheme would be updated of course). I have like a dozen of tables more.
All the examples I have found always specify the fields in the insert (:new.fieldX).
The keyword here is NOT to specify column names, right? In my opinion, you should because that's the only way you can control it.
the remote scheme would be updated of course
is kind of dangerous. WHAT IF it doesn't happen? "Of course" works until it does not work.
Sample tables (both are empty):
SQL> create table foo (id number, name varchar2(20));
Table created.
SQL> create table remote_foo as select * From foo where 1 = 2;
Table created.
If you use a trigger which is an autonomous transaction, then it won't see :new pseudorecord (as this is an autonomous transaction; right?); to this trigger, select * from foo where id = :new.id; won't return anything and remote_foo remains empty:
SQL> create or replace trigger trg_ai_foo
2 after insert on foo
3 for each row
4 declare
5 pragma autonomous_transaction;
6 begin
7 insert into remote_foo select * from foo where id = :new.id;
8 commit;
9 end;
10 /
Trigger created.
SQL> insert into foo (id, name) values (1, 'Littlefoot');
1 row created.
SQL> select * from foo;
ID NAME
---------- --------------------
1 Littlefoot
SQL> select * from remote_foo; --> it remained empty
no rows selected
SQL>
Note that - if you specified columns - it would work (but that's not what you wanted):
SQL> create or replace trigger trg_ai_foo
2 after insert on foo
3 for each row
4 declare
5 pragma autonomous_transaction;
6 begin
7 insert into remote_foo (id, name) values (:new.id, :new.name);
8 commit;
9 end;
10 /
Trigger created.
SQL> insert into foo (id, name) values (2, 'Bigfoot');
1 row created.
SQL> select * from foo;
ID NAME
---------- --------------------
2 Bigfoot
SQL> select * from remote_foo;
ID NAME
---------- --------------------
2 Bigfoot
SQL>
So, what to do? Switch to a statement-level trigger (instead of a row-level): it doesn't have to be autonomous, but has to have something that will prevent duplicates to be inserted - for example, a NOT EXISTS clause:
SQL> create or replace trigger trg_ai_foo
2 after insert on foo
3 begin
4 insert into remote_foo
5 select * from foo a
6 where not exists (select null from remote_foo b
7 where b.id = a.id);
8 end;
9 /
Trigger created.
SQL> insert into foo (id, name) values (1, 'Littlefoot');
1 row created.
SQL> insert into foo (id, name)
2 select 2, 'Bigfoot' from dual union all
3 select 3, 'anat0lius' from dual;
2 rows created.
Result:
SQL> select * from foo;
ID NAME
---------- --------------------
2 Bigfoot
3 anat0lius
1 Littlefoot
SQL> select * from remote_foo;
ID NAME
---------- --------------------
1 Littlefoot
3 anat0lius
2 Bigfoot
SQL>

Execute select/insert statement within an IF clause Oracle

I need to execute some statements within the IF clause only if a table exists.
But the issue I am facing is, even when the condition is false, the statements are getting executed.
DECLARE
count_matching_row NUMBER := 0;
count_matching_tbl NUMBER := 0;
BEGIN
SELECT COUNT(*)
INTO count_matching_tbl
FROM user_tables
WHERE LOWER(table_name) = 'tab1';
IF(count_matching_tbl = 1)
THEN
SELECT COUNT (*)
INTO count_matching_row
FROM test1
WHERE ID IN (SELECT ID FROM tab1);
IF(count_matching_row = 0)
THEN
INSERT INTO review_case
SELECT
DISTINCT ID, d,e
FROM tab1
WHERE ID IS NOT NULL;
INSERT INTO review_case_payer
SELECT
a,b,c
FROM tab1
WHERE a IS NOT NULL;
COMMIT;
END IF;
END IF;
END;
/
Whenever I execute these statements, if the table 'tab1' exists it works fine.
If the table tab1 does not exist I get the error
"ORA-06550: line 13, column 14:
PL/SQL: ORA-00942: table or view does not exist"
I get similar errors for each line where I try to access table "tab1"
I tried with ref cursor but still the same, I cannot use it for insert statements.
Your error is due to the fact that you're using a table that may not exist; this error is thrown because the script has compile problems, not data problems, so the way you try to use the IF is not enough to handle your situation.
You need to use some dynamic SQL to handle an object that could not exist; for example, see the following.
If the table does not exist, nothing will be done:
SQL> select * from tab1;
select * from tab1
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> declare
2 vCountTab number;
3 begin
4 select count(1)
5 into vCountTab
6 from user_tables
7 where table_name = 'TAB1';
8
9 if vCountTab = 1 then
10 execute immediate 'insert into TAB1 values (1, 2)';
11 end if;
12 end;
13 /
PL/SQL procedure successfully completed.
If the table exists, the insert will be done:
SQL> create table tab1(a number, b number);
Table created.
SQL> declare
2 vCountTab number;
3 begin
4 select count(1)
5 into vCountTab
6 from user_tables
7 where table_name = 'TAB1';
8
9 if vCountTab = 1 then
10 execute immediate 'insert into TAB1 values (1, 2)';
11 end if;
12 end;
13 /
PL/SQL procedure successfully completed.
SQL> select * from tab1;
A B
---------- ----------
1 2
SQL>

Oracle pivoting unknown number of column before execution time

I have something like this:
id cod
1 a
1 b
1 c
2 d
2 e
3 f
3 g
and i need something like this:
id cod 1 cod 2 cod 3
1 a b c
2 d e
3 f g
you understand that there is no way to know how many column oracle will have to generate before the execution time.
You can use procedure p_pivot, code below. It dynamically builds view v_test based on your table.
Then you can select from this view like here:
Connected to Oracle Database 10g Release 10.2.0.4.0
SQL> execute p_pivot;
PL/SQL procedure successfully completed
SQL> select * from v_test;
ID COD1 COD2 COD3
---------- ----- ----- -----
1 a b c
2 d e
3 f g
Procedure (please change table name from test to your table name in code):
create or replace procedure p_pivot is
v_cols number;
v_sql varchar2(4000);
begin
select max(cnt) into v_cols
from (select count(1) cnt from test group by id);
v_sql :=
'create or replace view v_test as
with t as (select row_number() over (partition by id order by cod) rn, test.* from test)
select id';
for i in 1..v_cols
loop
v_sql := v_sql || ', max(decode(rn, '||i||', cod)) cod'||i;
end loop;
v_sql := v_sql || ' from t group by id';
execute immediate v_sql;
end p_pivot;
There is NO way how to do that. Oracle HAS to know the number of columns at the moment when it is compiling the query.
Imagine that you create a view using such a query. The view would have different number of columns each time you look at it.
Also there should be no way how to fetch data from such a query. Because you do not know how many columns have until you evaluate all the data in the table.
Hi You can use this query also.
--Creating test data
create table test_me(id_num number,val varchar2(10));
insert all
into test_me
values(1,'a')
into test_me values (1,'b')
into test_me values (1,'c')
into test_me values (2,'d')
into test_me values (2,'e')
into test_me values (3,'f')
into test_me values (3,'g')
select 1 from dual;
select * from
(
select id_num,val,row_number() over (partition by id_num order by val) rn
from test_me )
pivot (max(val) for id_num in(1 as val_1,2 as val_2,3 as val_3));
The SQLFiddle demo is here
http://sqlfiddle.com/#!4/4206f/1

Oracle Type Error with Select Into

I'm using Oracle 10g and I'm getting some issues with codes that are suppose to work. It's driving me crazy. The code goes like this:
CREATE OR REPLACE TRIGGER trig_t1
AFTER INSERT ON t1
DECLARE
count1 INTEGER;
foo t1.field1%TYPE; --field is a VARCHAR2(20)
BEGIN
SELECT COUNT(1) INTO count1 --error in this line
FROM t1
WHERE condition;
foo:='bar';
UPDATE t1 SET field1=foo --error in this line
WHERE some condition ;
END;
It "compiles with errors", all are of the type of "PLS-00382: expression is of wrong type".
I just don't get it... Does anybody know what's wrong with my code?
Can you post the definition of T1? Your code seems to work fine for me if T1 has a single column named FIELD1. Is it possible that you have a column in the table that shares the name with a local variable?
SQL> create table t1( field1 varchar2(20) );
Table created.
SQL> create or replace trigger trg_t1
2 after insert on t1
3 declare
4 l_count1 integer;
5 foo t1.field1%type;
6 begin
7 select count(*)
8 into l_count1
9 from t1;
10
11 foo := 'bar';
12
13 update t1
14 set field1 = foo
15 where 1=1;
16 end;
17 /
Trigger created.
SQL> insert into t1 values( 'foo' );
1 row created.
SQL> select * from t1;
FIELD1
--------------------
bar

Resources