The problem statement: The user would specify a name based on which I have to pull names of two tables from a table and then extract values from those tables.I have created a pl/sql procedure for that and since the select query can return n number of rows I'm using Bulk Collect. I have created and object based on the fields I want to extract. Now the problem is that the columns are common in both the tables, so if I don't use alias I get ambiguous column error and if I use that I get the error of unimplemented feature.
here's my code:
create or replace type recon_obj_vib
is object (RECON_TABLE_KEY NUMBER(19)
,RECON_CHGLOGATTR_IDXLST VARCHAR2(1000 CHAR));
create or replace type recon_tab_vib
is table of recon_obj_vib;
create or replace PROCEDURE noMatchReport_proc(tableDesc IN VARCHAR2)
IS
l_recon_tab_vib recon_tab_vib := recon_tab_vib();
n Integer :=0;
out varchar2(2000);
tableName1 varchar2(25);
tableName2 varchar2(25);
tableDesc_without_space varchar2(25);
tableDesc_ra varchar2(25);
BEGIN
tableDesc_without_space:=Regexp_Replace(tableDesc,'\s');
tableDesc_ra:=UPPER('RA_' || tableDesc_without_space || ' %');
out:= 'Select recon_table_name from recon_tables where recon_table_desc = (:value) and rownum=1 and RECON_TABLE_name like (:userName)';
execute immediate out into tableName1 USING tableDesc,tableDesc_ra;
out:= 'Select recon_table_name from recon_tables where recon_table_desc = (:value) and rownum=1 and RECON_TABLE_name not like (:userName)';
execute immediate out into tableName2 USING tableDesc,tableDesc_ra;
out:='Select a.RECON_TABLE_KEY,a.RECON_CHGLOGATTR_IDXLST BULK COLLECT INTO l_recon_tab_vib from ' || tableName1 || ' a , ' || tableName2 || ' b where a.RE_KEY = b.RE_KEY and rownum=1';
execute immediate out into l_recon_tab_vib;
FOR i IN 1..l_recon_tab_vib.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE('RECON_TABLE_KEY '|| l_recon_tab_vib(i).RECON_TABLE_KEY ||' RECON_CHGLOGATTR_IDXLST ' || l_recon_tab_vib(i).RECON_CHGLOGATTR_IDXLST );
END LOOP;
END;
This part:
out:='Select a.RECON_TABLE_KEY,a.RECON_CHGLOGATTR_IDXLST BULK COLLECT INTO l_recon_tab_vib from ' || tableName1 || ' a , ' || tableName2 || ' b where a.RE_KEY = b.RE_KEY and rownum=1';
execute immediate out into l_recon_tab_vib;
Should be:
out:='Select a.RECON_TABLE_KEY,a.RECON_CHGLOGATTR_IDXLST from '
|| tableName1 || ' a , ' || tableName2
|| ' b where a.RE_KEY = b.RE_KEY and rownum=1';
execute immediate bulk collect into l_recon_tab_vib;
i.e. the BULK COLLECT INTO clause is part of the calling PL/SQL not part of the dynamic SQL.
Related
I have an existing table and I want to add some entry in another table for each row of the given first table.
I am writing my PLSQL command as:
BEGIN
FOR record in (select cola_guid, hapc_guid, tar_guid from tabA) LOOP
select count(*) INTO v_record_exists
from p where
p.cola_guid = record.cola_guid;
IF v_record_exists = 0 THEN
execute immediate 'insert into NTABLE (tar_guid, PC_NAE, PCV) values (record.tar_guid, ' || '''abcd''' || ', ' || '''val1''' || ')';
ELSE
execute immediate 'insert into NTABLE (tar_guid, PC_NAE, PCV) values (record.tar_guid, ' || '''abcd''' || ', ' || '''val2''' || ')';
END IF;
execute immediate 'insert into NTABLE (tar_guid, PC_NAE, PCV) values (record.tar_guid, ' || '''RA_hapc_guid''' || ', record.hapc_guid)';
execute immediate 'insert into NTABLE (tar_guid, PC_NAE, PCV) select record.tar_guid, PC_NAE, PCV from p where record.cola_guid = p.cola_guid and PC_NAE = ' || '''propVal''' || ' ';
END LOOP;
END;
Now I am getting error:
ORA-00984: column not allowed here
in line:
execute immediate 'insert into NTABLE (tar_guid, PC_NAE, PCV) values (record.tar_guid, ' || '''abcd''' || ', ' || '''val1''' || ')';
I am new to PLSQL world but I really tried triaging and googling but wasn't able to resolve. Please guide and help.
There is no need for you to use dynamic sql here - you know all the columns and tables you're inserting/selecting from, so you can simply use the PL/SQL variables directly in the SQL statement.
Also, when you're writing SQL inside PL/SQL, for performance reasons (as well as easy to read, maintain and debug) you should think set based.
It's entirely possible to do all your inserts in a single insert statement, which you can put inside a procedure.
BEGIN
INSERT INTO ntable (tar_guid, pc_nae, pcv)
WITH results AS (SELECT t.cola_guid,
t.hapc_guid,
t.tar_guid,
CASE WHEN EXISTS (SELECT NULL FROM p WHERE p.cola_guid = t.cola_guid) THEN 'val1' ELSE 'val2' END val
FROM taba t)
SELECT tar_guid,
'abcd' pc_nae,
val pcv
FROM results
UNION ALL
SELECT tar_guid,
'RA_hapc_guid' pc_nae
hapc_guid pcv
FROM results
UNION ALL
SELECT p.tar_guid,
p.pc_nae,
p.pcv
FROM results r
inner JOIN p ON r.cola_guid = p.cola_guid
WHERE p.pc_nae = 'propVal';
END;
/
Don't forget you'll need to commit/rollback as required!
A generic way to remove perfectly duplicated rows from all tables owned by a certain user.
Here's the stored procedure for it. Don't forget to replace 'YOUR_USERNAME_HERE' with your username.
CREATE OR REPLACE PROCEDURE DELETE_DUPLICATES_FROM_DB
IS
TABLE_COLUMNS VARCHAR2(10000);
DELETE_STATEMENT VARCHAR2(10000);
CURSOR ALL_MY_TABLES IS SELECT TABLE_NAME FROM ALL_TABLES WHERE OWNER = 'YOUR_USERNAME_HERE';
BEGIN
FOR MY_TABLE IN ALL_MY_TABLES
LOOP
SELECT LISTAGG(COLUMN_NAME, ',') WITHIN GROUP (ORDER BY 1) INTO TABLE_COLUMNS FROM USER_TAB_COLUMNS WHERE TABLE_NAME = MY_TABLE.TABLE_NAME;
DELETE_STATEMENT := 'DELETE FROM ' || MY_TABLE.TABLE_NAME || ' WHERE ROWID NOT IN (SELECT MIN(ROWID) FROM ' || MY_TABLE.TABLE_NAME || ' GROUP BY ' || TABLE_COLUMNS || ');';
EXECUTE IMMEDIATE DELETE_STATEMENT;
DBMS_OUTPUT.PUT_LINE(DELETE_STATEMENT);--print the statements we run
END LOOP;
END;
I get all the time an problem with the following snipped from my PL/SQL procedure
I need the variables to create an dynamic SQL statement, but i also need the nested table.
l_code list_code := list_code();
l_code := PKG_DATA.GET_CODES(in_code) ;
v_sql := 'SELECT ' || in_var_name ||'
FROM view
WHERE supplier = '||in_supplier ||'
AND factory = '|| in_factory ||'
AND code IN ('|| ( SELECT * FROM TABLE(l_code) )||') ';
EXECUTE IMMEDIATE v_sql
INTO v_value;
v_value is an nested table
[Error] PLS-00103 (60: 46): PLS-00103: Encountered the symbol "SELECT"
when expecting one of the following:
( - + case mod new not null continue, [Error] PLS-00103
(60: 74): PLS-00103: Encountered the symbol ")" when expecting one of
the following:
, ; for
as group having intersect minus order start union wh
Does anyone have an idea or an snipped ?
thx
v_sql := 'SELECT ' || in_var_name
|| ' FROM view '
|| ' WHERE supplier = :supplier AND factory = :factory '
|| ' AND code IN (SELECT * FROM TABLE(PKG_DATA.GET_CODES(:code)))';
EXECUTE IMMEDIATE v_sql INTO v_value USING in_supplier, in_factory, in_code;
I suggest using bind variables
v_sql := 'SELECT :in_var_name
FROM view
WHERE supplier = :in_supplier
AND factory = :in_factory
AND code IN (SELECT * FROM TABLE(:l_code) )) ';
EXECUTE IMMEDIATE v_sql
INTO v_value
USING in_var_name, in_supplier, in_factory, l_code;
But chances are, that you don't need dynamic SQL at all:
SELECT in_var_name
INTO v_value
FROM view
WHERE supplier = in_supplier
AND factory = in_factory
AND code IN (SELECT * FROM TABLE(l_code));
There are 4 tables
Table1(Column11, Column12, Column13)
Table2(Column21, Column22)
Table3(Column31, Column32,column33)
Table4(Column21, Column22)
And the following Mapping Table:
Table5(Sourcetable,Source column ,Destination table ,Destination column)
How to insert data from Table1 as source table and destination table as Table2,table3,table,4, Through Procedures?
I am using oracle 11g. Please help to achieve this!
If I understand your question, this is what you are looking for:
CREATE OR REPLACE PROCEDURE cpy_table
AS
CURSOR targ_dest_relation IS
SELECT sourcetable, sourcecolumn, destinationtable, destinationcolumn FROM table5;
BEGIN
FOR rec IN targ_dest_relation loop
execute immediate 'insert into ' || rec.destinationtable || '(' || rec.destinationcolumn || ') select ' || rec.sourcecolumn || ' from ' || rec.sourcetable;
END loop;
END;
/
SQL Fiddle
I have problem with mu procedure which insert duplicate last record in table
example when I put INSERT..... 'AAA' I got to rows in table 'AAA' and 'AAA'
In place when I put DBMS()... in code I got tow records
I use trigger and sequence for column ID in HistoriaDismissDate but they are in good condition. I check if I dropped trigger and sequence and its the same situation
I also use viewDate but this view get mi ONE record not two
my code
CREATE OR REPLACE PROCEDURE ChangeDismissDate
IS
v_id VARCHAR2(11);
v_dateBhd DATE := TO_DATE('20491231','yyyymmdd');
v_dateDismiss DATE := TO_DATE('20491231','yyyymmdd');
v_login VARCHAR2(50);
last_id NUMBER :=0;
CURSOR cur IS
select EMP_NO, LOGIN, ODEJSCIE_BHD, ODEJSCIE_OLD FROM viewDate;
BEGIN
OPEN cur;
LOOP
FETCH cur INTO v_id,v_login,v_dateBhd,v_dateDismiss;
DBMS_OUTPUT.put_line(v_id || ' ' || v_login || ' ' || v_dateBhd || ' ' || v_dateDismiss);
UPDATE employee_tab SET DISMISS_DATE = v_dateBhd WHERE EMP_NO = v_id;
COMMIT;
INSERT INTO HistoriaDismissDate(CUSTOMER_ID,LOGIN, DATE_CHANGE, DATE_BHD, DATE_DISMISS)
VALUES(v_id,v_login, sysdate, v_dateBhd, v_dateDismiss);
COMMIT;
EXIT WHEN cur%NOTFOUND;
END LOOP;
CLOSE cur;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
DBMS_OUTPUT.put_line (DBMS_UTILITY.format_error_stack);
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (DBMS_UTILITY.format_error_stack);
END;
/
2 tips on your original code:
1) cursor is a very old programming technic on PL/SQL. Prefer to use FOR ... LOOP construction. It's cleaner and less error-prone! See how it works:
CREATE OR REPLACE PROCEDURE ChangeDismissDate IS
BEGIN
for cur in (select EMP_NO, LOGIN, ODEJSCIE_BHD, ODEJSCIE_OLD FROM viewDate) loop
DBMS_OUTPUT.put_line(cur.EMP_NO || ' ' || cur.login || ' ' || cur.ODEJSCIE_BHD || ' ' || cur.ODEJSCIE_OLD);
UPDATE employee_tab
SET DISMISS_DATE = cur.ODEJSCIE_BHD
WHERE EMP_NO = cur.EMP_NO;
INSERT INTO HistoriaDismissDate
( CUSTOMER_ID,LOGIN, DATE_CHANGE, DATE_BHD, DATE_DISMISS )
VALUES
( cur.EMP_NO, cur.LOGIN, sysdate, cur.ODEJSCIE_BHD, cur.ODEJSCIE_OLD, );
end loop;
end;
/
2) Never, I mean never put a commit inside your procedure. The commit should be done on the caller block or on your client-side app. When you put a commit inside your procedure, you miss the chance to rollback after running it and other procedures could not call it if they want to control the transaction flow.