I have written a PL/SQL Procedure which compares data between two tables and print the difference if any, but the twist is the table names to the procedure is dynamic. Here is the procedure
create or replace PROCEDURE compareTables(
tabA IN VARCHAR2, tabB IN VARCHAR2) AS
cur_tab_name USER_TABLES%ROWTYPE;
lv_sql varchar2(4000);
lv_sql2 varchar2(4000);
BEGIN
--SELECT TABLE_NAME INTO cur_tab_name FROM USER_TABLES WHERE TABLE_NAME = tabA;
lv_sql2 := 'SELECT TABLE_NAME FROM USER_TABLES WHERE TABLE_NAME = :b_tabA';
EXECUTE IMMEDIATE lv_sql2 INTO cur_tab_name USING tabA;
<<child>>
DECLARE
TYPE cursor_ref IS REF CURSOR;
cur_comp_result cursor_ref;
rec_comp_result cur_tab_name.TABLE_NAME%rowtype;
BEGIN
lv_sql := 'SELECT * FROM '||tabA||' MINUS SELECT * FROM '||tabB;
OPEN cur_comp_result FOR lv_sql;
LOOP
FETCH cur_comp_result INTO rec_comp_result;
EXIT WHEN cur_comp_result%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(rec_comp_result.empid || '' || rec_comp_result.name);
END LOOP;
CLOSE cur_comp_result;
Exception
When others then
dbms_output.put_line('The Problem is '||sqlerrm);
END;
END compareTables;
Now the problem is when I compile this procedure I am getting the following error
Error at line 14: PLS-00310: with %ROWTYPE attribute, 'CUR_TAB_NAME.TABLE_NAME' must name a table, cursor or cursor-variable
line 14:rec_comp_result cur_tab_name.TABLE_NAME%rowtype;
how will I solve it?
*NB: I don't have oracle installed in my system. I am using Oracle Apex Online tool which uses
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 and
PL/SQL Release 11.2.0.3.0
As a test, go to the last line, and after the semicolon, hit enter.
I know that Pro*C in particular will gag without a line terminator at the end of the file.
You may be encounting that issue.
Outside the scope of your question consider
SELECT columns
FROM TABLE1
MINUS
SELECT columns
FROM TABLE2
and
SELECT columns
FROM TABLE2
MINUS
SELECT columns
FROM TABLE1
Use: cur_tab_name.table_name. The variable CUR_TAB_NAMEis of type USER_TABLE%ROWTYPE, thus it has several fields.
Related
Using Oracle SQL Developer. I have the following sample working:
DECLARE
v_next_TransId INTEGER; -- declare
BEGIN
select (max(Transaction_ID)+1) into v_next_TransId from xxpos.pos_transactions;
dbms_output.Put_line(v_next_TransId); --display
END;
Now I want to use that variable in an insert and/or select, I tried with and without a : prefix. The sample below gives me the ORA-01008: not all variables found.
DECLARE
v_next_TransId INTEGER; -- declare
BEGIN
select (max(Transaction_ID)+1) into v_next_TransId from xxpos.pos_transactions;
dbms_output.Put_line(v_next_TransId); --display
-- insert new row will go here
-- commit will go here
-- now verify the insert worked okay
--select * from xxpos.pos_transactions where Transaction_ID = ( select max(Transaction_ID) from xxpos.pos_transactions )
select * from xxpos.pos_transactions where Transaction_ID = :v_next_TransId;
END;
Without the : in front of the variable, I get this syntax error:
Versions:
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
PL/SQL Release 11.2.0.4.0 - Production
In PLSQL code block, columns of select statement have to be assigned to variables. You have to use select into clause your plsql code block as shown below.
DECLARE
v_next_TransId INTEGER; -- declare
l_pos_transactions xxpos.pos_transactions%ROWTYPE;
BEGIN
select (max(Transaction_ID)+1) into v_next_TransId from xxpos.pos_transactions;
dbms_output.Put_line(v_next_TransId); --display
-- insert new row will go here
-- commit will go here
-- now verify the insert worked okay
--select * from xxpos.pos_transactions where Transaction_ID = ( select max(Transaction_ID) from xxpos.pos_transactions )
select * into l_pos_transactions
from xxpos.pos_transactions where Transaction_ID = :v_next_TransId;
DBMS_OUTPUT.PUT_LINE(l_pos_transactions.column1|| ',' || l_pos_transactions.column2);
END;
I have 50 columns in one table and need to update each column.
Trying the below plsql code. (commented update section is working).
But dynamically generated column is not accepting.
(PL/SQL: ORA-01747: invalid user.table.column, table.column, or column specification)
Anybody can help please?
DECLARE
cursor udas is
select 5109 as udaid from dual
union all
select 8209 as udaid from dual;
BEGIN
for uda in udas loop
DECLARE
cursor c1 is
select
x.item, x.uda_id, x.uda_value, x.uda_value_desc
from
hp2_uda_data x
where
x.uda_type='LOV'
and x.uda_id=uda.udaid;
begin
for i in c1 loop
begin
/*update testtable set item_uda_5109_v=i.uda_value,
item_uda_5109_d=i.uda_value_desc where item_code=i.item;*/
update testtable set 'item_uda_'||uda.udaid||'_v'=i.uda_value,
'item_uda_'||uda.udaid||'_d'=i.uda_value_desc where item_code=i.item;
end;
end loop;
commit;
end;
end loop;
END;
Dynamic code requires execute immediate:
execute immediate
'update testtable
set item_uda_'||uda.udaid||'_v = :b1
, item_uda_'||uda.udaid||'_d = :b2
where item_code = :b3'
using i.uda_value, i.uda_value_desc, i.item;
It can be useful to construct the dynamic code in a variable so that you can report or log it in the event of failure.
I also recommend looking into code indentation as a useful technique for making code readable.
When I am running this Netezza stored procedure, I am getting an error
attribute 'SOME_VALUE' not found
As per requirement I have to get value from one table (TABLE_A) and insert into another table (TABLE_B).
This is the procedure:
create or replace procedure my_proc()
returns boolean
execute as owner
language NZPLSQL
as
BEGIN_PROC
declare rec RECORD ;
BEGIN
for rec in SELECT * from TABLE_A loop
EXECUTE IMMEDIATE
'INSERT INTO TABLE_B(COLUMN_B)
values( '|| rec.COLUMN_A_OFTABLE_A || ')';
END LOOP;
END;
END_PROC;
execute my_proc()
Here below, I am able to insert a string. But I need to insert different value depending on other table as I mentioned above.
EXECUTE IMMEDIATE 'INSERT INTO TABLE_B(COLUMN_B) values( ''Y'');';
When building a string that you are going run EXECUTE IMMEDIATE against, you have be careful to have everything quoted properly. In your case it's thinking that it needs to treat SOME_VALUE as an attribute/column, and it can't any column with that name.
Wrap your column reference in quote_literal() and it will interpret the contents of your column and quote-escape it properly for you.
create or replace procedure my_proc()
returns boolean
execute as owner
language NZPLSQL
as
BEGIN_PROC
declare rec RECORD ;
BEGIN
for rec in SELECT * from TABLE_A loop
EXECUTE IMMEDIATE
'INSERT INTO TABLE_B(COLUMN_B)
values( '|| quote_literal(rec.COLUMN_A_OFTABLE_A) || ')';
END LOOP;
END;
END_PROC;
You can find some more information in the documentation here.
Note: I am assuming that you have some more complicated logic to implement in this stored procedure, because looping over row by row will be much, much slower that insert..select. Often by an order of magnitude.
I am trying to create database by my java application using my generated schema file. In schema I have included drop query also. But I want to do some improvements for DROP QUERY. So I want to check the existence of db objects before running drop query and drop only when if it exists.
I googled for it and found some oracle link, Some link suggest following syntax and some mentioned that ORACLE does not support such syntax.
SYNTAX A:
IF EXISTS DROP TABLE TABLE_NAME
SYNTAX B:
DROP [TEMPORARY] TABLE [IF EXISTS]
tbl_name [, tbl_name] ...
[RESTRICT | CASCADE]
I also tried following queries:-
IF EXISTS (SELECT * FROM dba_objects WHERE OBJECT_NAME = 'BBB' )
DROP TABLE [BBB]
but it was giving error:-
Error starting at line 2 in command:
DROP TABLE [BBB]
Go
Error report:
SQL Error: ORA-00903: invalid table name
00903. 00000 - "invalid table name"
*Cause:
*Action:
Error starting at line 1 in command:
IF EXISTS (SELECT * FROM dba_objects WHERE OBJECT_NAME = 'BBB' ) DROP TABLE [BBB]
Error report:
Unknown Command
I refered following links:-
https://community.oracle.com/thread/2421779?tstart=0
Please suggest me if there any other queries to drop table with condition if table exists.
Drop table with no check. If any error exists you'll never know when something went wrong.
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE my_table';
EXCEPTION
WHEN OTHERS THEN
NULL;
END;
Or you can search in Oracle dictionary.
DECLARE
l_cnt NUMBER;
BEGIN
SELECT count(*)
INTO l_cnt
FROM user_tables
WHERE table_name = 'MY_TABLE';
IF l_cnt = 1 THEN
EXECUTE IMMEDIATE 'DROP TABLE my_table';
END IF;
END;
If you run following code you do not have to check if table exists and in case of errors (table is locked with now wait or any other you will know about it)
begin
for c1 in (select owner,table_name from dba_tables where table_name='MY_TABLE') loop
execute immediate 'drop table '||c1.owner||'.'||c1.table_name||'';
end loop;
end;
Try this : It will drop table 'table_name' if it is present .
declare
a varchar2(700) ;
begin
execute immediate ' SELECT CASE WHEN tab = 1
THEN ''DROP TABLE TABLE_NAME''
ELSE ''select 1 from dual''
END
FROM ( SELECT sum(case when table_name = ''TABLE_NAME'' then 1 else 0 end ) as tab FROM user_tables)' into a;
EXECUTE IMMEDIATE a;
end;
I am tasked with inserting a new transaction_code into a table which contains a min_cost and max_cost from the same table. What I am trying to do is take the min_cost from counties with a transaction code of 2 and the max_cost from counties with a transaction_code of 4. Here is what I am so far.
I wrote the errors that I am getting as comments next to the line in which I am getting them. I also tried using the arrays as tables, I didnt think it would work but I left them in there so you would understand what I attemped (they are commented out).
declare
type cost_min_array IS TABLE OF court_cost.cost_range_min%type INDEX BY BINARY_INTEGER;
type cost_max_array IS TABLE OF court_cost.cost_range_max%type INDEX BY BINARY_INTEGER;
v_min_cost cost_min_array;
v_min_cost cost_max_array;
BEGIN
begin
select cost_range_min -- SQL STATEMENT IGNORED
bulk collect into v_min_cost
from court_cost
where state = 'IL'
and transaction_code = 4
and end_date is null
order by county
EXCEPTION WHEN OTHERS THEN --SQL COMMAND NOT PROPERLY ENDED
v_min_cost.delete;
END;
BEGIN
select cost_range_max -- SQL STATEMENT IGNORED
bulk collect into v_max_cost
from court_cost
where state = 'IL'
and transaction_code = 2
and end_date is null
order by county
EXCEPTION WHEN OTHERS THEN -- SQL COMMAND NOT PROPERLY ENDED
v_max_cost.delete;
END;
for indx in 1..v_min_cost.count
loop
insert into court_cost -- SQL STATEMENT IGNORED
(TRANSACTION_CODE,
STATE,
COUNTY,
COST_RANGE_MIN,
BEGIN_DATE,
END_DATE,
DATE_INSERTED,
COURT,
COST_RANGE_MAX)
select lcc.TRANSACTION_CODE,
lcc.STATE,
lcc.COUNTY,
v_min_cost(indx),
lcc.BEGIN_DATE,
lcc.END_DATE,
lcc.DATE_INSERTED,
lcc.COURT,
v_max_cost(indx)
from court_cost lcc
-- cost_min_array cmn,
-- cost_max_array cmx
end loop; -- SQL COMMAND NOT PROPERLY ENDED
end; -- ENCOUNTERED THE SYMBOL ; WHEN EXPECTING LOOP
Any push in the right direction will be greatly appreciated, thanks.
You have missed semicolons thrice in the code which is resulting in the errors . In code down I have added them please check is code runs now. The statement ignored is coming because semi colon is not added at the end of it and even the exception section is considered in the same statement that's why giving error.
declare
type cost_min_array IS TABLE OF court_cost.cost_range_min%type INDEX BY BINARY_INTEGER;
type cost_max_array IS TABLE OF court_cost.cost_range_max%type INDEX BY BINARY_INTEGER;
v_min_cost cost_min_array;
v_min_cost cost_max_array;
BEGIN
begin
select cost_range_min -- SQL STATEMENT IGNORED
bulk collect into v_min_cost
from court_cost
where state = 'IL'
and transaction_code = 4
and end_date is null
order by county--semi colon added
EXCEPTION WHEN OTHERS THEN --SQL COMMAND NOT PROPERLY ENDED
v_min_cost.delete;
END;
BEGIN
select cost_range_max -- SQL STATEMENT IGNORED
bulk collect into v_max_cost
from court_cost
where state = 'IL'
and transaction_code = 2
and end_date is null
order by county--semi colon added
EXCEPTION WHEN OTHERS THEN -- SQL COMMAND NOT PROPERLY ENDED
v_max_cost.delete;
END;
for indx in 1..v_min_cost.count
loop
insert into court_cost -- SQL STATEMENT IGNORED
(TRANSACTION_CODE,
STATE,
COUNTY,
COST_RANGE_MIN,
BEGIN_DATE,
END_DATE,
DATE_INSERTED,
COURT,
COST_RANGE_MAX)
select lcc.TRANSACTION_CODE,
lcc.STATE,
lcc.COUNTY,
v_min_cost(indx),
lcc.BEGIN_DATE,
lcc.END_DATE,
lcc.DATE_INSERTED,
lcc.COURT,
v_max_cost(indx)
from court_cost lcc;--semi colon added
-- cost_min_array cmn,
-- cost_max_array cmx
end loop; -- SQL COMMAND NOT PROPERLY ENDED
end; -- ENCOUNTERED THE SYMBOL ; WHEN EXPECTING LOOP
You're missing semi-colons after your SQL statements. Try
declare
type cost_min_array IS TABLE OF court_cost.cost_range_min%type INDEX BY BINARY_INTEGER;
type cost_max_array IS TABLE OF court_cost.cost_range_max%type INDEX BY BINARY_INTEGER;
v_min_cost cost_min_array;
v_min_cost cost_max_array;
BEGIN
begin
select cost_range_min -- SQL STATEMENT IGNORED
bulk collect into v_min_cost
from court_cost
where state = 'IL'
and transaction_code = 4
and end_date is null
order by county; -- semi-colon added
EXCEPTION WHEN OTHERS THEN --SQL COMMAND NOT PROPERLY ENDED
v_min_cost.delete;
END;
BEGIN
select cost_range_max -- SQL STATEMENT IGNORED
bulk collect into v_max_cost
from court_cost
where state = 'IL'
and transaction_code = 2
and end_date is null
order by county; -- semi-colon added
EXCEPTION WHEN OTHERS THEN -- SQL COMMAND NOT PROPERLY ENDED
v_max_cost.delete;
END;
for indx in 1..v_min_cost.count
loop
insert into court_cost -- SQL STATEMENT IGNORED
(TRANSACTION_CODE,
STATE,
COUNTY,
COST_RANGE_MIN,
BEGIN_DATE,
END_DATE,
DATE_INSERTED,
COURT,
COST_RANGE_MAX)
select lcc.TRANSACTION_CODE,
lcc.STATE,
lcc.COUNTY,
v_min_cost(indx),
lcc.BEGIN_DATE,
lcc.END_DATE,
lcc.DATE_INSERTED,
lcc.COURT,
v_max_cost(indx)
from court_cost lcc; -- semi-colon added
-- cost_min_array cmn,
-- cost_max_array cmx
end loop; -- SQL COMMAND NOT PROPERLY ENDED
end; -- ENCOUNTERED THE SYMBOL ; WHEN EXPECTING LOOP
and see if that improves things.
Share and enjoy.