plsql: How to use an array variable in cursor - arrays

The following code is a sub-part of a bigger code where the array modify_column_list is declared and includes the column names of the table beset_e_szerepmatrix.
declare
cursor v_cur is select * from delta_stage.beset_e_szerepmatrix;
v_rec delta_stage.beset_e_szerepmatrix%rowtype;
begin
open v_cur;
loop
fetch v_cur into v_rec;
exit when v_cur%notfound;
v_sql := null;
for i in 1..modify_column_list.count loop
if v_sql is null and v_rec.modify_column_list(i) = 0 then
v_sql := modify_column_list(i);
else
if v_sql is not null and v_rec.modify_column_list(i) = 0 then
v_sql := v_sql || ', ' || v_rec.modify_column_list(i);
end if;
end if;
end loop;
v_rec.adathianyos_mezo := v_sql;
end loop;
close v_rec;
end;
Every columns include 0 or 1 value in the table beset_e_szerepmatrix. In the column adathianyos_mezo should include all column names, where the record has 0 value. How can I use the modify_column_list(i) in the cursor?

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

pgSQL update current row in cursor with table name as parameter for the update statement

I am writing a function in pgSQL and inside this function there is cursor that goes over a table row by row and if a condition is fulfilled then the row is updated like this:
UPDATE company SET code = 5 WHERE CURRENT OF company_cursor;
but the table name is a parameter passed to the function and I know I can use
Execute function something like this:
Execute 'UPDATE ' || table_name || ' SET code = 5 WHERE CURRENT OF company_cursor';
but the problem is that using 'CURRENT OF company_cursor' with Execute function is giving syntax error.
and my function is like this:
CREATE or replace FUNCTION fun(table_name TEXT)
RETURNS integer AS $$
DECLARE
cnt integer DEFAULT 0;
curr_rec RECORD;
prev_rec RECORD;
mycursor REFCURSOR;
query1 text;
BEGIN
OPEN mycursor for EXECUTE query1 ;
LOOP
FETCH mycursor INTO curr_rec;
EXIT WHEN NOT FOUND;
if cnt > 0 then
if prev_rec.code = curr_rec.code then
UPDATE company SET code = 1 WHERE CURRENT OF mycursor;
end if;
end if;
prev_rec := curr_rec;
cnt := cnt + 1;
END LOOP;
CLOSE mycursor;
return 1;
END; $$
LANGUAGE plpgsql;
So can someone please tell me how to use 'CURRENT OF' in this case ?

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;

Getting error while using two cursors

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;

PL/SQL How to convert a record to an assoc array

I am trying to fetch data from a table(employee) with cursor and save to asso. array. However, fetching data with cursor to a record is more straight-forward and it is troublesome to convert a record to an assoc array(arr). Code below is what I am trying to fetch data to a assoc array and improvement is needed. Or any approaches other than cursor? Thank you.
DECLARE
TYPE AssoArray IS TABLE OF varchar2(30) INDEX BY varchar2(30);
arr AssoArray;
table_rec employee%rowtype;
CURSOR cur IS
SELECT * FROM employee;
BEGIN
OPEN cur;
LOOP
FETCH cur into table_rec;
EXIT WHEN cur%notfound;
-- how to improve the code in the section below,
arr('col1') := table_rec.col1;
arr('col2') := table_rec.col2;
arr('col3') := table_rec.col3;
...
arr('col50') := table_rec.col50;
-- end of section
-- do sth
END LOOP;
END;
Could you explain what do you want to get. But I see in your code arr AssoArray will contain only one last fetched row and will be rewrite each cycle. Are you realy need it? My suggestion is you want to get some rows of table as associated array. If its true, you may create the array as table of rowtype and (for example) indexed it by id(if you ID-s is integer).
TYPE AssoArray IS TABLE OF employee%rowtype INDEX BY PLS_INTEGER;
For example
create table tmp_table_01 as select * from all_objects where rownum < 11;
DECLARE
TYPE AssoArray IS TABLE OF tmp_table_01%rowtype INDEX BY varchar2(30);
arr AssoArray;
table_rec tmp_table_01%rowtype;
CURSOR cur IS
SELECT * FROM all_objects where rownum < 20;
BEGIN
OPEN cur;
LOOP
FETCH cur into table_rec;
EXIT WHEN cur%notfound;
-- how to improve the code in the section below,
arr(table_rec.object_name) := table_rec;
-- end of section
dbms_output.put_line(table_rec.object_name ||' '||arr(table_rec.object_name).object_id );
-- do sth
END LOOP;
END;
EDIT:
If you want to make comraisons by table structure you may use Dynamic SQL. NExt code get data from table TMP_TABLE_01 sort it by object_id, compare neighbour rows, and return count of difference row.
DECLARE
l_sql varchar2(32767);
TYPE t_cols_type IS table of varchar2(30);
l_cols t_cols_type ;
l_result number;
BEGIN
SELECT c.COLUMN_NAME
BULK COLLECt INTO l_cols
FROM user_tab_cols c
WHERE c.TABLE_NAME = 'TMP_TABLE_01';
l_sql := 'WITH s AS (SELECT t.*, row_number() OVER (ORDER BY object_id) AS rn FROM TMP_TABLE_01 t)
SELECT count(*)
FROM s
JOIN s sub_s ON s.rn = sub_s.rn - 1
where 1=0 ';
FOR i IN 1 .. l_cols.last LOOP
l_sql := l_sql || ' OR decode(s.'||l_cols(i)||',sub_s.'||l_cols(i)||',1,0) = 0';
END LOOP;
dbms_output.put_line(l_sql);
EXECUTE IMMEDIATE l_sql
INTO l_result ;
dbms_output.put_line('count of conseuence different rows ' ||l_result);
END;

Resources