there is a SEQUENCE named test_seq.
SELECT TO_NUMBER('-'||TO_CHAR(test_seq.currval)) from DUAL; // can work
ALTER SEQUENCE test_seq INCREMENT BY TO_NUMBER('-'||TO_CHAR(test_seq.currval)); // wrong!
can I use function(like: TO_NUMBER() or TO_CHAR()) in ALTER statement?
No, you cannot. The railroad diagram disallows it.
You can accomplish it with EXECUTE IMMEDIATE statement in a block as shown.
DECLARE
next_increment NUMBER := TO_NUMBER('-'||TO_CHAR(test_seq.currval));
BEGIN
EXECUTE IMMEDIATE 'ALTER SEQUENCE test_seq INCREMENT BY '||next_increment;
END;
/
But make sure -
you have run test_seq.nextval atleast once before you execute this
block.
Use the sequence increment with caution . You might get the following
error if it goes below MINVALUE of the sequence.
ORA-08004: sequence TEST_SEQ.NEXTVAL goes below MINVALUE and cannot be instantiated
Related
Inquiring if there is a way to automatically set START WITH value of a sequence.
I want to drop and create the sequence since there is an error when inserting a row, problem is it affected all sequences hence we are unable to insert a row on multiple tables.
You can create small scripts like this when you create it :
-- Created on 18.10.2022 by ALI.FIDANLI
declare
-- Local variables here
i integer;
BEGIN
select max(cb_refno)+1 into i from dwh.customer_fact ;
dbms_output.put_line(i);
execute immediate
' create sequence SEQ_TEST minvalue 1 maxvalue 9999999999999999999999999999 start with '
|| i ||
' increment by 1 cache 20';
END;
Is it possible/make sense to have COMMIT statement in SQL functions?
Technically, the answer ist yes. You can do the following:
create or replace function committest return number as
begin
update my_table set col = 'x';
commit;
return 1;
end;
/
declare
number n;
begin
n := committest();
end;
/
However, you can't do the following:
select committest() from dual;
this would be a commit during a query and thus result in a
ORA-14552: Cannot Perform a DDL Commit or Rollback Inside a Query or DML
Yes, you can do that if you make the function an autonomous transaction. That way it will not be part of the current transaction anymore.
create or replace function doIt
as
pragma autonomous_transaction;
begin
... code ...
commit;
end;
/
More documentation
No, it's not possible, see the documentation:
https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_5009.htm
Restrictions on User-Defined Functions
.... In addition, when a function is called from within a query or DML
statement, the function cannot: ....
Commit or roll back the current transaction, create a savepoint or roll back to a savepoint, or alter the session or the system. DDL
statements implicitly commit the current transaction, so a
user-defined function cannot execute any DDL statements.
Here's a simple question about how to create a sequence with variables.
I wanna create a sequence using a combination of system time as it's start value. How should I do that.
Here's what I wrote:
DECLARE
SQS number :=(sysdate - to_date('01-JAN-1970','DD-MON-YYYY')) * (864000);
sql_stmt varchar2(200);
BEGIN
sql_stmt := 'create SEQUENCE XXXX_id_seq MINVALUE 100000 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH :1 CACHE 500 NOORDER CYCLE';
EXECUTE IMMEDIATE sql_stmt using SQS;
END;
but it says invalid num.
I know it's a noobie question. but I really need help here.
You can't bind variables in DDL statements (I ain't got doc or a good reason why, but quite a few references mentioning the fact), you've got to concatenate all in one.
DECLARE
SQS number :=(sysdate - to_date('01-JANV.-1970','DD-MON-YYYY')) * (864000);
sql_stmt varchar2(200);
BEGIN
sql_stmt := 'create SEQUENCE XXXX_id_seq MINVALUE 100000 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH '||SQS||' CACHE 500 NOORDER CYCLE';
EXECUTE IMMEDIATE sql_stmt ;
END;
I have a procedure in which 100 tables have to be updated one by one. All tables have the same column to be updated. For improving the performance I am trying to use Execute Immediate with FORALL but I am getting a lot of compilation errors.
Is it syntactically possible to update 100 different tables inside a FORALL statement using Execute immediate.
My code looks something like this.
Declare
TYPE u IS TABLE OF VARCHAR2(240) INDEX BY BINARY_INTEGER;
Table_List u;
FOR somecursor IN (SELECT variable1, variable2 FROM SomeTable)
LOOP
BEGIN
Table_List(1) := 'table1';
Table_List(2) := 'table2';
......
......
table_list(100):= 'table100';
FORALL i IN Table_List.FIRST .. Table_List.LAST
EXECUTE IMMEDIATE 'UPDATE :1 SET column = :3 WHERE column = :2'
USING Table_List(i), somecursor.variable1, somecursor.variable2 ;
end loop;
I hope people can understand what I am trying to do through this code. If something is big time wrong please suggest me what exactly is the syntax and if it can be done in some other efficient way also.
Thanks a lot for all the help which comes my way.
(1) No, you can't use a bind variable for the table name.
(2) When you're using EXECUTE IMMEDIATE, this implies Dynamic SQL - but FORALL requires that only one statement to be executed. As soon as you specify a different table, you're talking about a different statement (regardless of whether the tables' structures happen to be equivalent or not).
You're going to have to do this in an ordinary FOR loop.
Just a guess, but I don't think you can use a bind variable as a table name. Have you tried:
EXECUTE IMMEDIATE 'UPDATE ' || Table_List(i) || ' SET column = :2 WHERE column = :3' ...
I want to create a sequence in oracle where the max value of the column field (Empid) must be the min value of the sequence.
The below was the one i found in our same stackexchange
create sequence mytemp_seq start with &v_Startval;
This command prompts me to enter the max value of teh column name which i have to enter.
How can I fix the value of &v_startval with out it prompting ,but directly setting the values from the below statement
select max(empid) from mytemp..
I am trying like this below
create sequence mytemp_seq start with (SELECT MAX(empid) from mytemp)
But it doesnt work.
You could do it with some PL/SQL:
declare
v_startval integer;
begin
select max(empid)+1 into v_startval from mytemp;
execute immediate 'create sequence mytemp_seq start with ' || v_startval;
end;
In sqlplus you can do
col max_id new_value seq_min_val
SELECT MAX(empid)+1 AS max_id from mytemp;
create sequence mytemp_seq start with &seq_min_val;