execute immediate alter sequence not working - oracle

I'm stuck on this pretty simple script. It isn't working like I expect it to.
declare
st VARCHAR(1024);
begin
for x in (SELECT sequence_name FROM USER_SEQUENCES) loop
st := 'ALTER SEQUENCE ' || x.sequence_name || ' INCREMENT BY 1000';
execute immediate st;
st := 'select ' || x.sequence_name || '.nextval from dual';
execute immediate st;
st := 'ALTER SEQUENCE ' || x.sequence_name || ' INCREMENT BY 1';
execute immediate st;
end loop;
end;
/
When I run this it doesn't appear to work at all - all of my sequences just stay as they are, and they have not been incremented by a thousand by the dynamic statements. If I check nextval before and after the anonymous block, the difference is only 1, not 1001.
If I replace execute immediate with dbms_output.put_line and execute the generated commands manually the sequences are altered as I want.
What am I missing?

Both alter sequence statements are working, it's the increment in between that isn't happening. The nextval call in your loop is not being evaluated because the select statement isn't sending its output anywhere. From the documentation, a note that happens to refer to exactly what you are doing:
Note:
If dynamic_sql_statement is a SELECT statement, and you omit both into_clause and bulk_collect_into_clause, then execute_immediate_statement never executes.
For example, this statement never increments the sequence:
EXECUTE IMMEDIATE 'SELECT S.NEXTVAL FROM DUAL'
So you need to select that value into something:
declare
st VARCHAR(1024);
val number;
begin
for x in (SELECT sequence_name FROM USER_SEQUENCES) loop
st := 'ALTER SEQUENCE ' || x.sequence_name || ' INCREMENT BY 1000';
execute immediate st;
st := 'select ' || x.sequence_name || '.nextval from dual';
execute immediate st into val;
st := 'ALTER SEQUENCE ' || x.sequence_name || ' INCREMENT BY 1';
execute immediate st;
end loop;
end;
/
I've added a val variable, and an into val clause on the second execute immediate.
To demonstrate that it works now:
create sequence s42;
Sequence s42 created.
declare
st VARCHAR(1024);
n number;
begin
for x in (SELECT sequence_name FROM USER_SEQUENCES) loop
st := 'ALTER SEQUENCE ' || x.sequence_name || ' INCREMENT BY 1000';
execute immediate st;
st := 'select ' || x.sequence_name || '.nextval from dual';
execute immediate st into n;
st := 'ALTER SEQUENCE ' || x.sequence_name || ' INCREMENT BY 1';
execute immediate st;
end loop;
end;
/
anonymous block completed
select s42.nextval from dual;
NEXTVAL
----------
1001
Without the into clause, this came back with 1 rather than 1001, which is what you are seeing.

The restart start with syntax in 12c can simplify the steps:
create sequence test_sequence;
declare
st VARCHAR(1024);
begin
for x in (SELECT sequence_name, last_number FROM USER_SEQUENCES) loop
st := 'ALTER SEQUENCE ' || x.sequence_name
|| ' RESTART START WITH ' || to_char(x.last_number+1000);
execute immediate st;
end loop;
end;
/
select test_sequence.nextval from dual;
NEXTVAL
-------
1001

Related

Oracle : Delete rows with "execute immediate" and rowcount

I want to delete rows with an "Execute immediate" because the table name is in a variable.
How can I count the number of lines deleted?
I tried this, but it does not work with the INTO v_LINE_REMOVE;
v_sql := '
DELETE /*+parallel(t,4)*/
FROM "' || v_owner || '"."' || v_table_name ||'" t
where t."'|| v_column_name ||'" in (
select /*+parallel(rem,4)*/
rem.' || v_type_data || '
from ' || v_table_listeremove || ' rem
WHERE rem.dt_vact = '''|| v_dt_vact ||'''
)
';EXECUTE IMMEDIATE v_sql;--INTO v_LINE_REMOVE;
Thanks a lot
You should be able to use SQL%ROWCOUNT after running your DML statement
EXECUTE IMMEDIATE v_sql;
v_line_remove := SQL%ROWCOUNT;

PLSQL - FORALL in immediate execute

I want to use execute immediate for the forall syntax as i want to use the variable 'schemasname' instead of 'dcbhmoh1'.
Thanks
DECLARE
schemasname varchar2(25) := 'dcbhmoh1';
datet char(6) := '102024';
TYPE anames IS table of dcbhmoh1.F01131M%ROWTYPE;
ar anames;
BEGIN
EXECUTE IMMEDIATE 'SELECT * FROM ' || schemasname || '.F01131M WHERE ZMDTI >= ' || datet BULK COLLECT INTO ar;
dbms_output.put_line(ar.count);
IF ar.Count > 0 THEN
EXECUTE IMMEDIATE 'TRUNCATE TABLE ' || schemasname || '.F01131M';
FORALL i in ar.first .. ar.last INSERT INTO dcbhmoh1.F01131M VALUES ar(i);
END IF;
END;
You could try to define schema for your work session with
EXECUTE IMMEDIATE 'Alter session set current_schema='|| schemasname ;
Like this:
DECLARE
schemasname varchar2(25) := 'dcbhmoh1';
datet char(6) := '102024';
TYPE anames IS table of dcbhmoh1.F01131M%ROWTYPE;
ar anames;
BEGIN
-- set schema
EXECUTE IMMEDIATE 'Alter session set current_schema='|| schemasname ;
-- do your work
EXECUTE IMMEDIATE 'SELECT * FROM F01131M WHERE ZMDTI >= ' || datet BULK COLLECT INTO ar;
dbms_output.put_line(ar.count);
IF ar.Count > 0 THEN
EXECUTE IMMEDIATE 'TRUNCATE TABLE F01131M';
FORALL i in ar.first .. ar.last INSERT INTO F01131M VALUES ar(i);
END IF;
END;
(not sure about the complete syntax of the FORALL though).

Gettig error PLS-00364

I'm trying to create a stored procedure where I'm passing select statement to for loop and i'm using dynamic table which is passing at runtime and getting below error:
LINE 23 PLS-00364: loop index variable 'I' use is invalid
LINE 19 PL/SQL: ORA-00942: table or view does not exist
CREATE OR REPLACE PROCEDURE CREATE_TEST(TBL_NM IN VARCHAR2)
IS
SRC_ID NUMBER(38);
SQL_Q VARCHAR2(250);
DEL_F VARCHAR2(250);
BEGIN
FOR I in (SELECT DEL_IND FROM TBL_NM)
LOOP
SRC_ID := SRC_FILE_ID_SEQ.NEXTVAL;
IF I.DEL_IND = 0
THEN
execute immediate 'INSERT INTO TEST_HIST ' || ' (a,b,c,d,e,DEL_IND) ' ||
' SELECT a,b,c,d,e, '|| 0 || ' || ' FROM ' || TBL_NM;
ELSIF I.DEL_IND = 1
THEN
execute immediate 'INSERT INTO JESTX_IGNR ' || ' (a,b,c,d,e,DEL_IND,SRC_ID_NO) ' ||
' SELECT a,b,c,d,e, '|| 2 ||' , '|| SRC_ID || ' FROM ' || TBL_NM;
END IF ;
END LOOP;
COMMIT;
END;
I call the procedure using:
EXEC CREATE_TEST('abc');
What you want is a REF CURSOR as you cannot use cursor for loop with dynamic sql.
I dont know the exact datatype for your column DEL_IND. Please declare accordingly.
Here is some more information on Oracle REF CURSORS.
Try below
CREATE OR REPLACE PROCEDURE CREATE_TEST(TBL_NM IN VARCHAR2)
IS
TYPE c1ref is REF CURSOR;
SRC_ID NUMBER(38);
SQL_Q VARCHAR2(250);
DEL_F VARCHAR2(250);
DEL_IND NUMBER(5);
BEGIN
vsql_text := 'select DEL_IND from ' || TBL_NM;
open c1ref for vsql_text;
LOOP
SRC_ID := SRC_FILE_ID_SEQ.NEXTVAL;
fetch c1ref into DEL_IND;
exit when c1ref%NOTFOUND;
IF (DEL_IND = 0)
THEN
execute immediate 'INSERT INTO TEST_HIST ' || ' (a,b,c,d,e,DEL_IND) ' ||
' SELECT a,b,c,d,e, '|| 0 || ' || FROM ' || TBL_NM;
ELSIF (DEL_IND = 1)
THEN
execute immediate 'INSERT INTO JESTX_IGNR ' || ' (a,b,c,d,e,DEL_IND) ' ||
' SELECT a,b,c,d,e, '|| 2 ||' , '|| SRC_ID || ' FROM ' || TBL_NM;
END IF ;
END LOOP;
CLOSE c1ref;
COMMIT;
END;

oracle procedure giving ORA-00905: missing keyword

I'm trying to create a generic procedure to synchronize sequences.
I want to call the procedure and pass name of table, column and sequence but my procedure won't run due to an error.
Procedure:
CREATE OR REPLACE PROCEDURE INCREMENT_SEQ(table_name in varchar2 , id_column in varchar2 , sequence_name in varchar2)
AS
current_value number;
seq_val number := -1;
begin
EXECUTE IMMEDIATE 'select max(' || table_name || '.' || id_column || ') into current_value from ' || table_name ;
WHILE current_value >= seq_val
LOOP
EXECUTE IMMEDIATE 'select ' || sequence_name || '.nextval into seq_val from dual';
end loop;
end;
when I run the script I'm having the following error:
Error at line 2
ORA-00905: missing keyword
ORA-06512: at "TGC100_DEV.INCREMENT_SEQ", line 6
ORA-06512: at line 1
Script Terminated on line 16.
But I have no idea how to solve. Any advice would be helpfull.
You should put INTO clause outside the query:
CREATE OR REPLACE PROCEDURE INCREMENT_SEQ(table_name in varchar2 , id_column in varchar2 , sequence_name in varchar2)
AS
current_value number;
seq_val number := -1;
begin
EXECUTE IMMEDIATE 'select max(' || table_name || '.' || id_column || ') from ' || table_name into current_value;
WHILE current_value >= seq_val
LOOP
EXECUTE IMMEDIATE 'select ' || sequence_name || '.nextval from dual' into seq_val;
end loop;
end;
EXECUTE IMMEDIATE 'select max(' || table_name || '.' || id_column || ') into current_value from ' || table_name ;
It is syntactically incorrect. The INTO clause should be outside of EXECUTE IMMEDIATE statement.
Something like,
EXECUTE IMMEDIATE 'your SQL statement' INTO variable USING value;
UPDATE It is better to have the dynamic SQL as a variable to avoid confusions with so many single quotes and concatenation in the EXECUTE IMMEDIATE statement itself.
The other answer by Aramilo was posted before my answer, but I got confused to see the INTO clause already outside the statement.
For developers, it is always a good practice to first check the dynamic SQL using DBMS OUTPUT before actually executing it. Thus, it saves a lot of time to debug the whole bunch of PL/SQL code. Once confirmed that the dynamic SQL formed is correct, remove the DBMS_OUTPUT and execute the PL/SQL code.

Reset auto increment sequence pl-sql

How can i reset auto increment primary key ?
I have a doc_id_seq and a doc_pk_trg trigger like that:
CREATE SEQUENCE doc_id_seq START WITH 1;
CREATE OR REPLACE TRIGGER doc_pk_trg
BEFORE INSERT ON TFIDF FOR EACH ROW
BEGIN
IF :NEW.doc_id IS NULL THEN
SELECT doc_id_seq.NEXTVAL INTO :NEW.doc_id FROM DUAL;
END IF;
END;
/
I want to learn reset the sequence . How can I do this ?
You could use the ALTER SEQUENCE syntax.
Tom Kyte explains how to do exactly this here:
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:1119633817597
Simply drop and then recreate the sequence.
This is how I would reset it
CREATE OR REPLACE PROCEDURE reset_sequence (
p_sequence_name IN VARCHAR2,
p_new_value IN NUMBER
)
AS
l_current_value NUMBER;
v_sequence_exists NUMBER;
BEGIN
SELECT 1
INTO v_sequence_exists
FROM user_sequences
WHERE sequence_name = p_sequence_name;
EXECUTE IMMEDIATE 'SELECT ' || p_sequence_name || '.nextval FROM dual'
INTO l_current_value;
/*Not possible to increment by 0 !*/
IF (p_new_value - l_current_value - 1) != 0
THEN
EXECUTE IMMEDIATE 'ALTER SEQUENCE '
|| p_sequence_name
|| ' INCREMENT BY '
|| (p_new_value - l_current_value - 1)
|| ' MINVALUE 0';
END IF;
EXECUTE IMMEDIATE 'SELECT ' || p_sequence_name || '.nextval FROM dual'
INTO l_current_value;
EXECUTE IMMEDIATE 'ALTER SEQUENCE ' || p_sequence_name || ' INCREMENT BY 1 ';
EXCEPTION
WHEN NO_DATA_FOUND
THEN
raise_application_error (-20001, 'Sequence does not exist');
END;
This has the added benefit over drop & recreate of not invalidating any dependant schema objects.
try this
alter table "table_name"
modify "id" generated always as identity restart start with 1;

Resources