populating variable value dynamically in oracle - oracle

i have four tables as below : I want to insert the variable value v_col into the table test.This variable name is stored in another table test_lkp.when i try to run the code i am getting an error. How to achieve this.
DROP TABLE TEST ;
DROP TABLE TEST_LKP;
DROP TABLE TEST_REF;
DROP TABLE TEST_Q;
CREATE TABLE TEST (COL VARCHAR2(10));
CREATE TABLE TEST_LKP (COL VARCHAR2(10));
CREATE TABLE TEST_REF (VAL VARCHAR2(10));
CREATE TABLE TEST_Q (ENAME VARCHAR2(10));
INSERT INTO TEST_LKP VALUES ('v_col');
INSERT INTO TEST_REF VALUES ('ENAME');
INSERT INTO TEST_Q VALUES ('TOM');
INSERT INTO TEST_Q VALUES ('JIM');
INSERT INTO TEST_Q VALUES ('MARK');
COMMIT;
Actual code :
SET SERVEROUTPUT ON;
declare
v_col VARCHAR2(30);
BEGIN
SELECT VAL INTO v_col FROM TEST_REF;
dbms_output.put_line(v_col);
EXECUTE IMMEDIATE
' INSERT INTO TEST SELECT '|| V_COL ||' FROM TEST_Q ' ;
END;
/
expectation is to build the insert statement dynamically through the look up table so that if any change in the columns can be handled through the look up table rather than modifying the script.
To achieve i have created the look up table TEST_LKP with the same structure as TEST and inserting values as V_COL.
This is what i tried
SET SERVEROUTPUT ON;
declare
v_col VARCHAR2(30);
q VARCHAR2(1000);
CURSOR c1 IS
SELECT
'INSERT INTO TEST '
||
'SELECT ' || COL || ' FROM TEST_Q ' DMLS
FROM TEST_LKP;
BEGIN
SELECT val INTO v_col FROM TEST_REF;
dbms_output.put_line(v_col);
FOR i IN c1
loop
dbms_output.put_line(i.DMLS);
execute immediate i.dmls;
end loop;
END;
/
erorr :
Error report -
ORA-00904: "V_COL": invalid identifier
ORA-06512: at line 17
00904. 00000 - "%s: invalid identifier"
*Cause:
*Action:
ENAME
INSERT INTO TEST SELECT v_col FROM TEST_Q
Expected :
i want v_col to be replaced with ENAME as
INSERT INTO TEST SELECT ENAME FROM TEST_Q
any solution for this ?

Related

Oracle trigger failed to access user_tab_columns

I am using Oracle 19c, and need to retrieve information from user_tab_columns in a trigger. There is no error when the trigger fires, however there is nothing returns back when query this system table.
create table mysche1.tb_test (id number(1), comment varchar2(20));
insert into mysche1.tb_test value (1, 'This is first line');
create or replace trigger mySche1.AUT_tb_test
after update on
mySche1.tb_test for each row
declare
cursor vco_col_nm
is
select column_name
form user_tab_columns
where table_name = 'tb_test'
colList varchar2(2048);
begin
for colNm in vco_col_nm loop
colList := colList || colNm.column_name || ',';
end loop;
mySche1.pack1.proc1 (colList); --I print out the colist in the PLSQL, which displays nothing.
end;
update mySche1.tb_test set comment = 'second' where id =1;

How to pass list of table names as parameter in stored procedure in Oracle SQL Developer? How to use PLSQL VARRAY or nested table?

I have a code which accepts a table name as parameter and creates subpartitions on that table name for the partitions. My table is partitioned on list of source system codes and range subpartitoned on monthly basis.
Question: If suppose I have variable list of tables and I want to create subpartitions for all then I need to modify this procedure every time to pass varying list of tables.
Can I use PLSQL VARRAY or nested table to hold my list of tables, and pass this VARRAY or nested table as a parameter to the below procedure and create subpartitions for all the table names the VARRAY or nested table is holding?
Your help is much appreciated. Many thanks!
Code:
CREATE OR REPLACE PROCEDURE execute_subpartition ( table_name IN varchar2)
IS
tbl_nm varchar2(30) := table_name;
sqlstr VARCHAR2(1000);
CURSOR TabSubPartition IS
SELECT TABLE_NAME, PARTITION_NAME
FROM USER_TAB_PARTITIONS
WHERE TABLE_NAME = tbl_nm
ORDER BY PARTITION_NAME;
BEGIN
FOR aSubPart IN TabSubPartition LOOP
IF TRUNC(LAST_DAY(SYSDATE)) = TRUNC(SYSDATE)
sqlstr := 'ALTER TABLE TUCEL001.' || aSubPart.TABLE_NAME || ' MODIFY PARTITION ' ||
aSubPart.PARTITION_NAME ||' ADD SUBPARTITION ' || aSubPart.PARTITION_NAME || '_' ||
TO_CHAR(TRUNC(LAST_DAY(SYSDATE) + 1), 'MON_YYYY') ||' VALUES LESS THAN (TIMESTAMP ''' ||
TRIM(to_char(add_months((TRUNC(LAST_DAY(SYSDATE))+1), 1), 'SYYYY-MM-DD HH24:MI:SS',
'NLS_CALENDAR=GREGORIAN')) || ''')';
dbms_output.put_line(sqlstr);
EXECUTE IMMEDIATE sqlstr;
ELSE
dbms_output.put_line('the condition did not match');
END IF;
END LOOP;
Exception
WHEN OTHERS
THEN
dbms_output.put_line('encountered an error, because the sub-partitions which are being created
already exists');
END;
My 11g doesn't have partitioning enabled so I can't demonstrate it.
But, see if this example (of creating some tables) helps. You don't have to declare your own type - sys.odcivarchar2list should do. Read it using the table function and use its column_value in your dynamic SQL.
Procedure:
SQL> create or replace procedure p_test (par_tables in sys.odcivarchar2list) as
2 l_str varchar2(200);
3 begin
4 for cur_r in (select column_value as table_name
5 from table(par_tables)
6 )
7 loop
8 dbms_output.put_line('table name = ' || cur_r.table_name);
9 l_str := 'create table ' || dbms_assert.qualified_sql_name(cur_r.table_name) ||
10 ' (id number,' ||
11 ' name varchar2(20))';
12 execute immediate(l_str);
13 end loop;
14 end;
15 /
Procedure created.
Testing:
SQL> exec p_test(sys.odcivarchar2list('tab_a', 'tab_b'));
PL/SQL procedure successfully completed.
SQL> desc tab_a;
Name Null? Type
----------------------------------------- -------- ----------------------------
ID NUMBER
NAME VARCHAR2(20)
SQL> desc tab_b;
Name Null? Type
----------------------------------------- -------- ----------------------------
ID NUMBER
NAME VARCHAR2(20)
SQL>

"ORA-01007: variable not in select list" when no rows are returned by EXECUTE IMMEDIATE

I have a procedure which receives as parameter a where clause (i.e. where col1 = 1). I am using this clause to search in some tables using an EXECUTE IMMEDIATE statement and the result to be inserted into a nested table, and than be displayed.
The procedure works fine if any data is found but in case no data is found, then the above error is thrown.
Can someone explain what cause this error, please?
Here is the procedure:
create or replace procedure prc_checks(pi_where varchar2) as
cursor c_tables is
select object_name,
case object_name
when 'XP_IMPORT_MW' THEN 99999999
when 'XP_IMPORT_MW_ARCH' THEN 99999998
else TO_NUMBER(SUBSTR(object_name, -8, 8))
end to_order
from dba_objects
where object_type = 'TABLE'
and object_name IN ('XP_IMPORT_MW', 'XP_IMPORT_MW_ARCH')
or REGEXP_LIKE (object_name, 'XP_IMPORT_MW_ARCH_201(5|6|7)[0-9]{4}') order by 2 desc;
type t_result is table of xp_import_mw%rowtype;
v_result t_result;
v_sql varchar2(300);
BEGIN
for i in c_tables
loop
v_sql := 'select * from ' || i.object_name || ' ' || pi_where;
execute immediate v_sql bulk collect into v_result;
if v_result.count > 0
then
for j in v_result.first .. v_result.last
loop
dbms_output.put_line(v_result(j).art_nr);
end loop;
dbms_output.put_line('... the required information was found on table name ' || upper(i.object_name));
exit;
end if;
end loop;
END prc_checks;
You'll get this is one of the tables being found by the cursor has fewer columns than xp_import_mw. For example:
create table xp_import_mw (col1 number, art_nr number, dummy number);
create table xp_import_mw_arch_20160102 (col1 number, art_nr number, dummy number);
create table xp_import_mw_arch_20160101 (col1 number, art_nr number);
insert into xp_import_mw_arch_20160101 values (1, 42);
So the main xp_import_mw table has three columns but no matching data. One of the old archive tables has one fewer columns.
I added a dbms_output.put_line(v_sql) to the procedure to see which table it fails against, then ran it:
set serveroutput on
exec prc_checks('where col1 = 1');
which got output:
select * from XP_IMPORT_MW where col1 = 1
select * from XP_IMPORT_MW_ARCH_20160102 where col1 = 1
select * from XP_IMPORT_MW_ARCH_20160101 where col1 = 1
Error starting at line : 49 in command -
BEGIN prc_checks('where col1 = 1'); END;
Error report -
ORA-01007: variable not in select list
ORA-06512: at "MY_SCHEMA.PRC_CHECKS", line 25
ORA-06512: at line 1
01007. 00000 - "variable not in select list"
*Cause:
*Action:
So the problem isn't that there is no data found; the problem is that there is matching data in a table which has the wrong structure.
You could construct the select list based on the xp_import_mw table's structure, instead of using *; that won't stop it failing, but would at least give you a slightly more helpful error message - in this case ORA-00904: "DUMMY": invalid identifier instead of ORA-01007.
You could do a quick and crude check for discrepancies with something like:
select table_name, count(column_id) as column_count,
listagg(column_name, ',') within group (order by column_id) as columns
from dba_tab_columns
where table_name IN ('XP_IMPORT_MW', 'XP_IMPORT_MW_ARCH')
or REGEXP_LIKE (table_name, 'XP_IMPORT_MW_ARCH_201(5|6|7)[0-9]{4}')
group by table_name
having count(column_id) != (
select count(column_id) from dba_tab_columns where table_name = 'XP_IMPORT_MW'
);
... although if you're using dba_* or all_* view you should really be including the owner, here and in your procedure.

ORACLE: How to insert into temp table, while using dynamic sql

I am using a few temp tables in Oracle to store some data, which is needed later in the function. To determine the data I need to store in the table, I am using a dynamic sql statement (using parameters as column names of other tables). I tried to different approaches.
The first time, I tried something like this:
INSERT INTO temp_tableA
EXECUTE IMMEDIATE dynamic_sql
USING IN OUT temp_tableB
And the other approach was like:
EXECUTE IMMEDIATE INTO temp_tableA
USING IN OUT temp_tableB
I already used some other temp table (temp_tableB) to store some data it seems, that it worked fine with the first approach, but there I did not have to use a dynamic sql statement. If I am trying to do it the same way with dynamic sql (so like the first approach) it tells me, that the keyword VALUES is missing.
The second try returns the error message, that temp_tableA can't be used as an INTO-target of a SELECT/FETCH-Statement.
What am I missing? I have to say, that I am quite new to Oracle and it's starting to drive me crazy :D
Say you have tables like the following:
create table someTab(colA number, colB number, colC number);
create table someOtherTab(col varchar2(10), val number);
insert into someTab values (1, 10, 100);
insert into someTab values (2, 20, 200);
You could define a procedure like this:
create or replace procedure copyProc(colName IN varchar2) is
vSQL varchar2(1000);
begin
vSQL := 'insert into someOtherTab(col, val) select ''' || colName || ''', ' || colName || ' from someTab';
--
dbms_output.put_line(vSQL);
execute immediate vSQL;
end;
It you run this procedure, this is what you get:
SQL> exec copyProc('colA');
insert into someOtherTab(col, val) select 'colA', colA from someTab
PL/SQL procedure successfully completed.
SQL> select * from someOtherTab;
COL VAL
---------- ----------
colA 1
colA 2
SQL> exec copyProc('colC');
insert into someOtherTab(col, val) select 'colC', colC from someTab
PL/SQL procedure successfully completed.
SQL> select * from someOtherTab;
COL VAL
---------- ----------
colA 1
colA 2
colC 100
colC 200

ORA-00904: Invalid identifier when using forall

When i run the following block, I get the error:
ORA-00904: Invalid identifier in "forall".
Can somebody please help me fix it?
The column "ID" is an 12c identity column, so number.
drop table t1 cascade constraints purge;
create table t1 (
c1 number
);
set serveroutput on;
declare
type l_t2 is table of number;
l_c1 l_t2;
begin
select ID
bulk collect into l_c1
from IDTABLE;
dbms_output.put_line('Number of records: ' || sql%rowcount);
forall i in l_c1.first..l_c1.last
insert into t1 values l_c1(i);
end;
/
You're missing parentheses around the PL/SQL table reference in the values clause. Change this line:
insert into t1 values l_c1(i);
to
insert into t1 values (l_c1(i));
Without them it thinks l_cl is a schema-level object of some kind, which doesn't exist; hence the error you see. With them it works:
set serveroutput on;
declare
type l_t2 is table of number;
l_c1 l_t2;
begin
select ID bulk collect into l_c1 from IDTABLE;
dbms_output.put_line('Number of records: ' || sql%rowcount);
forall i in l_c1.first..l_c1.last
insert into t1 values (l_c1(i));
end;
/
PL/SQL procedure successfully completed.
Number of records: 2

Resources