Getting error while using two cursors - database

Getting error while using two cursors
[Error] PLS-00103 (45: 48): PLS-00103: Encountered the symbol
"TX_COM_LOCATION" when expecting one of the following:
:= . ( # % ;
The symbol ":=" was substituted for
"TX_COM_LOCATION" to continue.
Please help

CREATE OR REPLACE PROCEDURE COM_LOCATION_TXM
IS
BEGIN
DECLARE CURSOR TXM_COM_LOCATION IS SELECT col1,col2,col3 from TBL_SAR_SALAS_1 A;
CURSOR TX_COM_LOCATION is select col1,col2,col3 from TBL_LOCALES B;
TMP_TXM TXM_COM_LOCATION%ROWTYPE;
TMP_TXM TX_COM_COCATION%ROWTYPE;
Begin
IF NOT TXM_COM_LOCATION%ISOPEN
THEN OPEN TXM_COM_LOCATION;
END IF;
FETCH TXM_COM_LOCATION INTO TMP_TXM;
EXIT
WHEN TXM_COM_LOCATION%NOTFOUND;
IF NOT TX_COM_LOCATION%ISOPEN
THEN
OPEN TXCOM_LOCATION;
END IF;
LOOP FETCH TX_COM_LOCATION INTO TMP_TX; EXIT WHEN TX_COM_LOCATION%NOTFOUND;
BEGIN Insert statement()
END;
END LOOP;
END LOOP;
commit;
END;
END COM_LOCATION_TXM ;

Check this:
CREATE OR REPLACE PROCEDURE COM_LOCATION_TXM IS BEGIN DECLARE CURSOR TXM_COM_LOCATION IS SELECT col1, col2, col3 FROM TBL_SAR_SALAS_1 A; CURSOR TX_COM_LOCATION IS SELECT col1, col2, col3 FROM TBL_LOCALES B; TMP_TXM TXM_COM_LOCATION%ROWTYPE; TMP_TXM TX_COM_LOCATION%ROWTYPE; BEGIN IF NOT TXM_COM_LOCATION%ISOPEN THEN OPEN TXM_COM_LOCATION; END IF; LOOP FETCH TXM_COM_LOCATION INTO TMP_TXM; EXIT WHEN TXM_COM_LOCATION%NOTFOUND; IF NOT TX_COM_LOCATION%ISOPEN THEN OPEN TXCOM_LOCATION; END IF; LOOP FETCH TX_COM_LOCATION INTO TMP_TX; EXIT WHEN TX_COM_LOCATION%NOTFOUND; BEGIN NULL; -- REPLACE NULL WITH INSERT STATEMENT END; END LOOP; END LOOP; COMMIT; END; END COM_LOCATION_TXM;

Related

select from table of varchar2

i have a type
create or replace TYPE "CUSTOM_DATA" IS TABLE OF VARCHAR2(4000) .
i can assign some values and print to output without problem
declare
cust_data CUSTOM_DATA;
begin
cust_data:=CUSTOM_DATA('A','B','C');
FOR i IN 1 .. cust_data.COUNT
LOOP
DBMS_OUTPUT.put_line (cust_data(i));
END LOOP;
end;
But how can i use cust_data in select clause , because i will assign them to a ref cursor , how can i do this? my code below is not working
SELECT COLUMN_VALUE as val FROM table(cust_data);
Your code works:
DECLARE
cust_data CUSTOM_DATA;
BEGIN
cust_data:=CUSTOM_DATA('A','B','C');
FOR i IN (SELECT COLUMN_VALUE as val FROM table(cust_data))
LOOP
DBMS_OUTPUT.put_line(i.val);
END LOOP;
END;
/
or:
DECLARE
cust_data CUSTOM_DATA;
cur SYS_REFCURSOR;
value VARCHAR2(4000);
BEGIN
cust_data:=CUSTOM_DATA('A','B','C');
OPEN cur FOR
SELECT COLUMN_VALUE as val FROM table(cust_data);
LOOP
FETCH cur INTO value;
EXIT WHEN cur%NOTFOUND;
DBMS_OUTPUT.put_line(value);
END LOOP;
END;
/
Which both output:
A
B
C
db<>fiddle here

Atomic Transaction with nested BEFORE INSERT/UPDATE Triggers

Currently i am implementing a procedure, which creates a couple of rows in some related tables out of a template. So my Procedure consists of a SAVEPOINT followed by some INSERT statements on different tables, and a Cursor to insert some more rows to other tables while referencing on the newly created primary keys.
Each of those tables has an BEFORE INSERT/UPDATE trigger defined which has the purpose to:
Get a new primary key from a sequencer if it is not defined in the INSERT statement (there are cases where I need to set the Primary key explicitely to reference it later on in the same transaction)
Set some default values if they are NULL
Set auditing fields (last_change_date, last_change_user, etc..)
The transaction fails with ORA-04091: table is mutating, trigger/function may not see it
I am understanding, that I could Workaround this, by declaring PRAGMA AUTONOMOUS TRANSACTION in each Trigger, but my Transaction would not be atomic any more then, as it is the requirement that all those datasets should be created/inserted as a whole or None of them.
So what am I doing wrong in the design of my database?
UPDATE: This is the Code of the trigger
CREATE TRIGGER TRG_AUFTRAG_B_IU
BEFORE INSERT OR UPDATE
ON AUFTRAG
FOR EACH ROW
BEGIN
IF INSERTING THEN
IF :new.id is NULL or :new.id = 0 THEN
SELECT SEQ_AUFTRAG.nextval into :new.id from dual;
END IF;
IF :new.nummer is NULL or :new.nummer = 0 THEN
SELECT nvl(MAX(NUMMER),0)+1 INTO :new.nummer FROM AUFTRAG WHERE EXTRACT(YEAR from DATUM) = EXTRACT(YEAR from :new.DATUM);
END IF;
--DEFAULT Values
IF :new.BETR_GRENZWERTE_RELEVANT is NULL THEN
SELECT 0 INTO :new.BETR_GRENZWERTE_RELEVANT FROM dual;
END IF;
IF :new.DOKUMENTE_ABGELEGT is NULL THEN
SELECT 0 INTO :new.DOKUMENTE_ABGELEGT FROM dual;
END IF;
IF :new.EXT_ORG is NULL or :new.EXT_ORG < 1 THEN
SELECT 1 INTO :new.EXT_ORG FROM dual;
END IF;
:new.ERSTELLT_VON := nvl(:new.ERSTELLT_VON,user);
:new.ERSTELLT_DATUM := nvl(:new.ERSTELLT_DATUM,sysdate);
END IF;
:new.GEAENDERT_VON := user;
:new.GEAENDERT_DATUM := sysdate;
END;
You can write it more compact like this:
CREATE TRIGGER TRG_AUFTRAG_B_IU
BEFORE INSERT OR UPDATE
ON AUFTRAG
FOR EACH ROW
BEGIN
IF INSERTING THEN
:new.id = NVL(NULLIF(:new.id, 0), SEQ_AUFTRAG.nextval);
--DEFAULT Values
:new.BETR_GRENZWERTE_RELEVANT := NVL(:new.BETR_GRENZWERTE_RELEVANT, 0);
:new.DOKUMENTE_ABGELEGT := NVL(:new.DOKUMENTE_ABGELEGT, 0);
IF :new.EXT_ORG is NULL or :new.EXT_ORG < 1 THEN
:new.EXT_ORG := 1;
END IF;
:new.ERSTELLT_VON := nvl(:new.ERSTELLT_VON,user);
:new.ERSTELLT_DATUM := nvl(:new.ERSTELLT_DATUM,sysdate);
END IF;
:new.GEAENDERT_VON := user;
:new.GEAENDERT_DATUM := sysdate;
END;
Only "problem" is this part
IF :new.nummer is NULL or :new.nummer = 0 THEN
SELECT nvl(MAX(NUMMER),0)+1 INTO :new.nummer
FROM AUFTRAG
WHERE EXTRACT(YEAR from DATUM) = EXTRACT(YEAR from :new.DATUM);
END IF;
This one you should put into your procedure or in a statement trigger (i.e. without FOR EACH ROW clause) like this:
CREATE TRIGGER TRG_AUFTRAG_B_A
AFTER INSERT ON AUFTRAG
BEGIN
UPDATE
(SELECT ID, NUMMER,
ROW_NUMBER() OVER (PARTITION BY EXTRACT(YEAR from DATUM) ORDER BY ID) as N
FROM AUFTRAG)
SET NUMMER = N
WHERE NUMMER IS NULL;
END;

Sql Server Transaction dont work correctly

I have a big problem with Sql Server (2008 R2).
In one database i have 3 table for example Tmp_table and T_Dest1 and T_Dest2
and I have 3 procedure that work with this 3 table
procedure Main()
Begin
Declare #Res_Two int, #Res_Tree Int;
Begin Transaction T_One;
do heavy work;
exec #Res_Two = two;--Call Procedure Two
if #Res_Two = -1
Begin
GoTo RB;
End;
do heavy work;
exec #Res_Three = Three;--Call Procedure Tree
if #Res_Three = -1
Begin
GoTo RB;
End;
Delete From Tmp_table;
if ##ERROR > 0
Begin
RB:
Rollback Tran T_One;
Return (-1);
End Else Begin
Commit Tran T_One;
Return (1);
End;
End;
End;
Procedure Two;
Begin
insert into T_Dest1 Select * from tmp_table ;
if ##ERROR > 0 Goto Rb;
if ##ERROR > 0
Begin
RB:
Return (-1);
End Else Begin
Return (1);
End
End;
Procedure Three;
Begin
insert into T_Dest2 Select * from tmp_table ;
if ##ERROR > 0 Goto Rb;
if ##ERROR > 0
Begin
RB:
Return (-1);
End Else Begin
Return (1);
End
End;
all things is OK, but suddenly when user call Main Proc data from tmp_table copy in T_Dest1 but dont copy in T_Dest2 and Main proc return 1 that means every thing is OK; (this state maybe occur one or two in day).
how i can what is incorrect in my db and what is my mistake?
this way that i use from transaction is correct?
can i find when data Lose from Tmp_Table and Main Proc don't work correctly?
i thinks this fault when my server is very busy and many users work with database together.
Here is some pseudocode using try/catch instead of GOTOs.
procedure Main()
Begin
Begin Transaction;
begin try
Declare #Res_Two int, #Res_Tree Int;
do heavy work;
exec two;--Call Procedure Two
do heavy work;
exec Three;--Call Procedure Tree
Delete From Tmp_table;
Commit Transaction;
end try
begin catch
rollback transaction
--Do some other to indicate the error like logging
--Do something to inform caller that an error happened (return statement or raiserror)
end catch
End;
Procedure Two;
Begin
insert into T_Dest1 Select * from tmp_table ;
End;
Procedure Three;
Begin
insert into T_Dest2 Select * from tmp_table ;
End;

Procedure in PL/SQL with create and cursor

Can we have a Procedure with
First create a table suppose
create table INCOME_GROUP(income_compare_groups varchar(100)) ;
Then insert data into this table.
insert into INCOME_GROUP values (10-20);
Then Use this table into a cursor.
CURSOR c1 IS(select *from INCOME_GROUP);
For Example I am doing this.
BEGIN
create table INCOME_GROUP(income_compare_groups varchar(100)) ;
DECLARE
CURSOR c1 IS(select * income_Group);
BEGIN
FOR acct IN c1 LOOP -- process each row one at a time
INSERT INTO temp_test
VALUES (acct.income_compare_groups);
END LOOP;
COMMIT;
END;
END;
But I am getting some Error.
ORA-06550: line 2, column 4:
PLS-00103: Encountered the symbol "CREATE" when expecting one of the following:
( begin case declare exit for goto if loop mod null pragma
raise return select update while with <an identifier>
<a double-quoted delimited-identifier> <a bind variable> <<
continue close current delete fetch lock insert open rollback
savepoint set sql execute commit forall merge pipe purge
After reading the comments I tried this -
BEGIN
EXECUTE IMMEDIATE 'create table INCOME_GROUP
(
income_compare_groups varchar(100)
)';
DECLARE
CURSOR c1 IS
(select * from
INCOME_GROUP
);
BEGIN
FOR acct IN c1 LOOP -- process each row one at a time
INSERT INTO temp_test
VALUES (acct.income_compare_groups, null);
END LOOP;
COMMIT;
END;
END;
But seems it is not creating table.!!!!
You can do it like this:
create or replace procedure cpy_inc_comp_grps
as
cur_1 sys_refcursor;
compare_group varchar2(100);
begin
execute immediate 'create table income_group(income_compare_groups varchar2(100))';
open cur_1 for 'select income_compare_groups from income_group';
LOOP
FETCH cur_1 INTO compare_group;
DBMS_OUTPUT.PUT_LINE('INSERT INTO temp_test VALUES (rec.income_compare_groups');
EXIT WHEN cur_1%NOTFOUND;
END LOOP;
close cur_1;
execute immediate 'drop table income_group';
end;
And test it with the following code:
begin
cpy_inc_comp_grps;
end;
You have to replace the dbms_output.put_line(...) part with whatever inserts you want to do.
It must be like this:
DECLARE
cur SYS_REFCURSOR;
v_income_compare_groups VARCHAR(100);
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE INCOME_GROUP(income_compare_groups VARCHAR(100))';
OPEN cur FOR 'SELECT * income_Group';
LOOP
FETCH cur INTO v_income_compare_groups;
EXIT WHEN cur%NOTFOUND;
INSERT INTO temp_test VALUES (v_income_compare_groups);
END LOOP;
CLOSE cur;
COMMIT;
END;
You have to use dynamic Cursor because when you compile the package then the table INCOME_GROUP does not exist yet and you would get an error at CURSOR c1 IS(select * income_Group);
However, there are several issue:
You will get an error if the table already exist. You have to check this first or write an exception handler.
The procedure is useless because you first create an (empty) table and then you select it - it will never select anything!
Try this.
execute immediate 'create table INCOME_GROUP(income_compare_groups varchar(100))';

PL/SQL querying a table on multiple databases

I'm a bit stuck. I have a table with a list of database names. I want to query for the database name and then query this database to return details from its "systemtable".
I've been trying to use 2 cursors but its not quite working out for me (just can't find the syntax), any pointers/help would be appreciated.
declare
cursor c_dbNames is select dbname
from DB_INFO order by name ASC;
v_curr_dbname VARCHAR2(60);
begin
open c_dbNames;
LOOP
FETCH c_dbNames into v_curr_dbname;
EXIT WHEN c_dbnames%NOTFOUND;
begin
cursor c_dbDetails is select value
from SYSTEMTABLE#'||v_curr_dbname||' order by name ASC;
v_curr_detail VARCHAR2(60);
open c_dbDetails;
LOOP
FETCH c_dbDetails into v_curr_detail;
EXIT WHEN c_dbDetails%NOTFOUND;
htp.p('<tr><th>'||v_curr_detail||'</th></tr>');
END LOOP;
close c_dbDetails;
end;
END LOOP;
close c_dbnames;
end;
You have to adjust it a little:
declare
cursor c_dbNames is
select 'dual' dbname from dual union all
select 'dual' dbname from dual union all
select 'dual' dbname from dual
order by dbname ASC;
v_curr_dbname VARCHAR2(60);
begin
open c_dbNames;
LOOP
FETCH c_dbNames into v_curr_dbname;
EXIT WHEN c_dbnames%NOTFOUND;
DECLARE
v_cursor integer;
v_rows integer;
v_curr_detail char(20);
begin
v_cursor := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(v_cursor, 'select ''c_dbDetails'' c_dbDetails FROM ' || v_curr_dbname, DBMS_SQL.NATIVE);
DBMS_SQL.DEFINE_COLUMN_CHAR(v_cursor, 1, v_curr_detail, 20);
v_rows := DBMS_SQL.EXECUTE(v_cursor);
loop
if DBMS_SQL.FETCH_ROWS(v_cursor) = 0 then
exit;
end if;
DBMS_SQL.COLUMN_VALUE_CHAR(v_cursor, 1, v_curr_detail);
DBMS_OUTPUT.PUT_LINE('<tr><th>' || v_curr_detail ||'</th></tr>');
end loop;
DBMS_SQL.CLOSE_CURSOR(v_cursor);
end;
END LOOP;
close c_dbnames;
end;
declare
cursor databases_c is
-- put your database links here
select 'XXX' as dbname from dual union
select 'YYY' from dual;
v_global_name varchar2(4000);
begin
for v_dbname in databases_c loop
-- query the database details
execute immediate
'select global_name from global_name#' || v_dbname.dbname
into v_global_name;
dbms_output.put_line(v_global_name);
end loop;
end;
/
Output:
SQL> #so27.sql
XXX
YYY
PL/SQL procedure successfully completed.
SQL>

Resources