How to reset sequence if the table is empty? [duplicate] - sql

This question already has answers here:
How do I reset a sequence in Oracle?
(18 answers)
Closed 5 years ago.
I am using Oracle SQL. There is a sequence and trigger used for id that increments from 1 every time a new record is added in the table. However if all the records are deleted and new records to be added this table, the id doesn't starts from 1 whilst it starts from the last maximum number of records recorded in the sequence.
Therefore is there a way in TRIGGER statement where I can reset the sequence if the table is empty and new records get imported.
OR do I have to do stored_procedure way, if that then how can i call this using myBatis mapper?
Table (customer_info)
customer_id customer_name customer_location
1 Arbin USA
2 Tim Canada
3 Rachel Australia
Sequence
CREATE sequence customer_id_seq START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
Trigger
CREATE OR REPLACE TRIGGER customer_id
BEFORE INSERT ON customer_info
FOR EACH ROW
BEGIN
SELECT customer_id_seq.NEXTVAL
INTO :new.customer_id
FROM dual;
END;
/
Thank you.

Once You Truncate the Table. The Sequence has to be Reset to 1.
The simplest way to do it it by dropping and re-creating it again.
DROP SEQUENCE customer_id_seq
CREATE sequence customer_id_seq START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;

Related

Increment by 1 in sequence numbering and dynamically partitioned tables

I am using dynamically created table partitions to store event information in a Postgresql 13 database. The master table from which the child tables inhert their structure contains an id field with an auto-incrementing sequence. The sequence, master table and trigger for inserts look as follows:
CREATE SEQUENCE event_id_seq
INCREMENT 1
START 1
MINVALUE 1
MAXVALUE 9223372036854775807
CACHE 1;
CREATE TABLE event_master
(
id bigint NOT NULL DEFAULT nextval('event_id_seq'::regclass),
event jsonb,
insert_time as timestamp
)
CREATE TRIGGER insert_event_trigger
BEFORE INSERT
ON event_master
FOR EACH ROW
EXECUTE PROCEDURE event_insert_function();
Additionally, the event_insert_function() uses the following code to insert new rows posted to the master table:
EXECUTE format('INSERT INTO %I (event, insert_time) VALUES($1,$2)', partition_name) using NEW.event, NEW.insert_time);
When looking at the sequence numbers in the id field, I only get every other number, i.e. 1,3,5,7, ...
Based on some related information I found, I assume this has something to do with Postgresql counting the initial insert into the master table and the triggered insert into the child table as two occurences. So my first question is, whether this is correct, and if so what's the rational behind it and why not "pass through" the insert from master to child?
More importantly though, what do I need to do to set up a properly incrementing sequence (i.e. returning 1,2,3,4 ...)?

How to compare and update an inserted value to existing value using a trigger?

I am learning triggers for the first time in SQL, and I am unsure of how to write/phrase a certain trigger.
I am attempting to make a trigger that would check to see if a value within an attempted row insert is greater than the existing value within the table, and then update the value if the new value being added to the table is greater than the current version of that value. So if a user were to try to insert a row containing an attribute with a value of 3 in table Z that contains that same attribute but with a value of 1, the values would be compared then table Z would be updated to have that attribute now have a value of 3.
Re your (now edited out) question about :old and :new - old and new are most applicable to update queries where they allow you to examine the before-update and after-update value of the same row - the scenario you're discussing is one of editing a different row using an insert so :old doesn't really apply - the insert trigger will only have a :new pseudorow. There wouldn't be an :old that refers to a different row existing in the table
Two ways you could do this with a "before insert" trigger - either:
find the existing row and if it exists, copy its data into the :new row then delete the existing row. This is an errorless way of handling the issue but is perhaps longer to code
issue an update query to update an existing row and if a row is updated, raise an application error to prevent the insert of the new row
For a discussion on before insert triggers that prevent inserts in some scenarios see Prevent Insert Trigger - and expect some said "don't use triggers" chatter; it's good advice. Every time I've used triggers a part of me wishes I hadn't :)
ps; I specifically haven't written the code for this for you because you've said it's a learning exercise, but if you feel you'll learn more by reading code from someone else rather than writing it out yourself, let me know and I'll provide some example. Tejash has made a reasonable start on the update route i describe, it just remains to use the sql%rowcount to know how many rows were updated and raise an exception to prevent the insert
I am not sure if I understood you correctly but this is what my understanding is from your question.
You have one table: Z (ATTRB, VAL)
You want to create an insert trigger on it.
The trigger should update the VAL of already existing record in case ATTRB of the existing record is same as ATTRB of newly inserted record and VAL of the existing record is lower than newly inserted record's VAL
The trigger should update the value of VAL of the existing record to the VAL of the newly inserted record.
Here is how you can do it using a trigger.
- creating the table and adding one record:
SQL> CREATE TABLE Z (ATTRB VARCHAR2(1), VAL NUMBER);
Table created.
SQL> INSERT INTO Z VALUES ('A',1);
1 row created.
SQL> SELECT * FROM Z;
A VAL
- ----------
A 1
- Trigger code
SQL> CREATE TRIGGER Z_TRG BEFORE
2 INSERT ON Z
3 FOR EACH ROW
4 BEGIN
5 UPDATE Z
6 SET VAL = :NEW.VAL
7 WHERE ATTRB = :NEW.ATTRB
8 AND VAL < :NEW.VAL;
9 END Z_TRG;
10 /
Trigger created.
- Checking if the trigger is working by inserting other value
SQL> INSERT INTO Z VALUES ('A',2); -- adding higher value of VAL should update the existing record
1 row created.
SQL> SELECT * FROM Z;
A VAL
- ----------
A 2
A 2
SQL> INSERT INTO Z VALUES ('A',1); -- adding lower value of VAL will do nothing
1 row created.
SQL> SELECT * FROM Z;
A VAL
- ----------
A 2
A 2
A 1
SQL>
Cheers!!

Difference in Assigned and Start value in a Sequence

I have created a sequence
CREATE SEQUENCE CA_SEQUENCE_NUMBER_SEQ
start with 9000000000
increment by 1
nocycle
nocache;
The assigned and the start values are the same number. Kindly suggest me what could be the reason
please refer to the image for the clear picture.
this image details are from SYSSEQUENCES Data dictionary view
I would assume that the sequence has been altered. E.g.
CREATE SEQUENCE CA_SEQUENCE_NUMBER_SEQ AS DECIMAL(31,0) start with 7000000000;
values nextval for CA_SEQUENCE_NUMBER_SEQ;
ALTER SEQUENCE CA_SEQUENCE_NUMBER_SEQ restart with 9000000000;
then SYSCAT.SEQUENCES would show
select NEXTCACHEFIRSTVALUE from syscat.sequences where seqname = 'CA_SEQUENCE_NUMBER_SEQ'"
NEXTCACHEFIRSTVALUE
---------------------------------
7000000000.
1 record(s) selected.
but after another call to values nextval for CA_SEQUENCE_NUMBER_SEQ, the NEXTCACHEFIRSTVALUE will update
values nextval for CA_SEQUENCE_NUMBER_SEQ;
1
---------------------------------
9000000000.
1 record(s) selected.
select NEXTCACHEFIRSTVALUE from syscat.sequences where seqname = 'CA_SEQUENCE_NUMBER_SEQ'"
NEXTCACHEFIRSTVALUE
---------------------------------
9000000020.
1 record(s) selected.
It appears that the create statement happened some time ago as >700,000 numbers have been generated from the sequence. It is possible to restart a sequence from anywhere by issuing an ALTER SEQUENCE statement such as:
ALTER SEQUENCE CA_SEQUENCE_NUMBER_SEQ RESTART 7000000000
You can point it back to the starting value specified in the CREATE SEQUENCE statement by using just RESTART like this:
ALTER SEQUENCE CA_SEQUENCE_NUMBER_SEQ RESTART
Here is the relavant section of the documentation:
>>-ALTER SEQUENCE--sequence-name-------------------------------->
.-----------------------------------------------.
V (1) |
>----------+-RESTART--+------------------------+-+-+-----------><
| '-WITH--numeric-constant-' |
RESTART
Restarts the sequence. If numeric-constant is not specified, the sequence is restarted at the value specified implicitly or explicitly as the starting value on the CREATE SEQUENCE statement that originally created the sequence.
WITH numeric-constant
Restarts the sequence with the specified value. This value can be any positive or negative value that could be assigned to a column of the data type associated with the sequence (SQLSTATE 42815), without nonzero digits existing to the right of the decimal point (SQLSTATE 428FA).

table mutating in oracle

I have a table, participated, which has a trigger that returns the total damage amount for a driver id when a new record is inserted into the table.
create or replace trigger display
after insert on participated
for each row
declare
t_id integer;
total integer;
begin
select driver_id, sum(damage_amount)
into t_id, total
from participated
where :new.driver_id = driver_id
group by driver_id;
dbms_output.put_line(' total amount ' || total' driver id' || t_id);
end;
/
The trigger is created, but it returns this error:
ORA-04091: table SQL_HSATRWHKNJHKDFMGWCUISUEEE.PARTICIPATED is mutating,
trigger/function may not see it ORA-06512: at
"SQL_HSATRWHKNJHKDFMGWCUISUEEE.DISPLAY", line 5
ORA-06512: at "SYS.DBMS_SQL", line 1721
Please help with this trigger.
As commented above, this feels like a code-smell. A row level trigger cannot change the table being changed, since that would fire another trigger, which would end up in an endless loop of calling triggers.
Changing this to a statement level trigger is not doing the same thing.
Preferred solution:
1) put this to the application logic, and calculate after row has been inserted - this is trivial as #kfinity mentioned.
2) earmark newly inserted rows and use a statement level trigger. For example, have an extra column, say is_new default 1 - therefore all new inserted rows will have this flag. Then use a statement level trigger suggested by #hbourchi to calculate and update all drivers that is_new is 1, and then set this flag back to zero
3) the logic in 2) can be implemented using pl/sql and in-memory pl/sql tables. The pl/sql table collects affected driver ids using a row level trigger, and then updates the totals of the selected drivers. Tom Kyte has lots of examples on this, this is not a rocket science, however if you lack of PL/SQL knowledge, then this is probably not your way. (For the note: PL/SQL is super important when using Oracle - without that Oracle is just an expensive Excel sheet like any other db. Worth of using it.)
4) probably, you shall revise your data model - and the problem solves itself. The participated table shows multiple rows per driver id. You want to calculate one total row per driver id - why would you put that summary to the same table? Simply add a new table, participated_total which has driver_id and damaged_amount fields. Then feel free to insert or update that from your trigger as you planned originally!
5) in fact, you can calculate these totals on the fly (depending on the number of rows and your performance expectations), by simply crafting the right SQL when querying - this way no need to store the pre-calculated totals.
6) but if you wish Oracle to store these totals for you, you can do 5) and use materialized views. These are in-fact tables, which are updated and maintained automatically by Oracle, so your actual query at 5) does not need to calculate anything on the fly but can get the automatically pre-calculated data from the materialized view.
How about just no triggers at all ?
SQL> create table participated (
2 incident_id int primary key,
3 driver_id int not null,
4 damage_amount int not null
5 );
Table created.
SQL>
SQL> insert into participated
2 select rownum, mod(rownum,10), dbms_random.value(1000,2000)
3 from dual
4 connect by level <= 200;
200 rows created.
SQL> create materialized view log on participated with rowid, (driver_id,damage_amount), sequence including new values;
Materialized view log created.
SQL> create materialized view driver_tot
2 refresh fast on commit
3 with primary key
4 as
5 select driver_id,
6 sum(damage_amount) tot,
7 count(*) cnt
8 from participated
9 group by driver_id;
Materialized view created.
SQL> select driver_id, tot
2 from driver_tot
3 order by 1;
DRIVER_ID TOT
---------- ----------
0 32808
1 29847
2 28585
3 29714
4 32148
5 30491 <====
6 29258
7 32103
8 30131
9 26834
10 rows selected.
SQL>
SQL> insert into participated values (9999,5,1234);
1 row created.
SQL> commit;
Commit complete.
SQL>
SQL> select driver_id, tot
2 from driver_tot
3 order by 1;
DRIVER_ID TOT
---------- ----------
0 32808
1 29847
2 28585
3 29714
4 32148
5 31725 <====
6 29258
7 32103
8 30131
9 26834
10 rows selected.
SQL>
SQL>
You didn't post your trigger definition but normally you can not query a table, inside trigger when updating records in the same table.
Try using after update trigger. it might work in your case. Something like this:
CREATE OR REPLACE TRIGGER my_trigger AFTER UPDATE ON my_table FOR EACH ROW
DECLARE
...
BEGIN
...
END;
another option would be to make your trigger AUTONOMOUS_TRANSACTION:
CREATE OR REPLACE TRIGGER my_trigger BEFORE INSERT ON my_table FOR EACH ROW
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
...
END;
However read this before choosing for this option:
https://docs.oracle.com/cd/B14117_01/appdev.101/b10807/13_elems002.htm

Oracle sequences reset [duplicate]

This question already has answers here:
How do I reset a sequence in Oracle?
(18 answers)
Closed 6 years ago.
I've created a sequence in my Oracle database. It will increment by 1 every time when i started my application and inserted in the table. The table look like this:
create table COUNTERS_DELEGATION
(
counter_id NUMBER not null,
counter_number LONG not null,
current_date NUMBER not null
)
In the field current_date i will insert the current year.
My question is: When the year increment for example from 2016 to 2017 i want to start my sequence again from initial value 1. Is this possible?
If I understand your request correctly, you want to reset the sequence when the value of the sequence gets to 2017.
If so, I think you'll need to drop and recreate the sequence:
DROP SEQUENCE sequencename;
CREATE SEQUENCE sequencename
MINVALUE 1
MAXVALUE 2017
START WITH 1
INCREMENT BY 1
CYCLE;