Before you mark this a duplicate. I found this answer on another thread and having difficulties making it work.
From psql I see my table:
\d people
Table:
Column | Type | Modifiers
---------------+----------------------------------+-----------------------------------------------------------------------
id | integer | not null default
nextval('people_id_seq'::regclass)
Code I tried which seems to do nothing...
ALTER SEQUENCE people_id_seq RESTART 1000
How do I make the primary key start from 1000?
The following query would set the sequence value to 999. The next time the sequence is accessed, you would get 1000.
SELECT setval('people_id_seq', 999);
Reference:
Sequence Manipulation Functions on PostgreSQL Manual
Why are you declaring your id like that ?
I mean, I would do the following :
create table people(
id serial,
constraint primaryKeyID primary key(id));
And now if you want to start your sequence from 1000, your alter query will work.
alter sequence people_id_seq restart 1000
Related
I have an initialization script I use on Spring Boot application start and I create the table if it doesn't exist. Then I delete all the data from the table and execute a bunch on inserts.
create table if not exists employee (
id serial primary key,
name varchar(255)
);
delete from employee;
-- inserts
With each execution of the script, the sequence still continues, so the new rows don't start from one. I have to reset such sequence too, however, it is generated and I dont know its name unless I call this script:
select pg_get_serial_sequence('employee', 'id');
-- returns public.employee_id_seq
I tried to combine it together and reset the sequence based on the output of this funciton, but with no luck. How to reset the generated sequence without knowing its name? My attempt so far cannot resolve the seq sequence from the variable:
do $$
declare
seq varchar(255);
begin
select pg_get_serial_sequence('employee', 'employee_id') into seq;
alter sequence seq restart with 1;
end; $$;
The simplest solution is to use truncate table . . . restart identity instead of delete:
truncate table employee restart identity;
Here is a db<>fiddle.
Truncate table is recommended for other reasons too. For instance, it reclaims the space the table used immediately. And it is much faster. The one difference is that delete triggers are not called (although your table doesn't have any triggers).
It is basically a bad idea to reset a id serial to any number, so you must be very carefully using the following.
especially when you have foreign keys to the id firld
the camand you are looking for is
ALTER SEQUENCE <table_name>_<id_column>_seq RESTART WITH 1
create table if not exists employee (
id serial primary key,
name varchar(255)
);
INSERT INTO employee (name) VALUES ('a'),('B'),('C')
3 rows affected
delete from employee;
3 rows affected
ALTER SEQUENCE employee_id_seq RESTART WITH 1
INSERT INTO employee (name) VALUES ('a')
1 rows affected
SELECT * FROM employee
id | name
-: | :---
1 | a
db<>fiddle here
I am using PGsql and transferred some data from another database into my new one. The table has records starting at PK 200. The tables primary key (bigint - autoincrementing) is currently starting at 0. If I continue to insert records, eventually it will reach 200. My question is, will these records create an issue when trying to insert record 200? or will PGsql know the conflict, then find the next available AI index (say 234)?
Thanks! If it will cause a conflict, how can I set the current index of my table to the last index of data? (like 234).
My question is, will these records create an issue when trying to insert record 200?
Assuming that you have a serial column or the-like: yes, this will create an issue. The serial has no knowledge that some sequences are not available, sp this will result in a duplicate key error. Meanwhile the sequence increments also on such errors, and the next call will return the next number, and so on.
This is easily reproducible:
create table t (id serial primary key, val text);
insert into t (id, val) values (2, 'blocker');
-- 1 rows affected
insert into t (val) values ('foo');
-- 1 rows affected
insert into t (val) values ('bar');
-- ERROR: duplicate key value violates unique constraint "t_pkey"
-- DETAIL: Key (id)=(2) already exists.
insert into t (val) values ('baz');
-- 1 rows affected
select * from t order by id;
id | val
-: | :------
1 | foo
2 | blocker
3 | baz
One solution is to reset the sequence: the only safe starting point is the high watermark of the table:
select setval(
't_id_seq',
coalesce((select max(id) + 1 from t), 1),
false
);
Demo on DB Fiddlde: you can uncomment the setval() statement to see how it avoids the error.
Postgres database
I'm trying to find a faster way to create a new column in a table which is a copy of the tables primary key column, so if I have the following columns in a table named students:
student_id Integer Auto-Increment -- Primary key
name varchar
Then I would like to create a new column named old_student_id which has all the same values as student_id.
To do this I create the column and the execute the following update statement
update student set old_student_id=student_id
Which works, but on my biggest table it takes over an hour, and I feels like I should be able to use some kind of alternative approach to get that down to a few minutes, I just don't know what.
So what I want at the end of the day is something that looks like this:
+------------+-----+---------------+
| student_id | name| old_student_id|
+------------+-----+---------------+
| 1 | bob | 1 |
+------------+-----+---------------+
| 2 | tod | 2 |
+------------+-----+---------------+
| 3 | joe | 3 |
+------------+-----+---------------+
| 4 | tim | 4 |
+------------+-----+---------------+
To speed things up a bit before I do the update query, I drop all the FK's and Indices on the table, then reapply them when it finishes. Also I'm on an AWS RDS, so I have setup a param group which has synchronized_commits=false, turned off backups, and increased working mem a bit for the duration of this update.
For context this is actually happening to every table in the database, across three databases. The old ids are used as references for several external systems which reference these ids, so I need to keep track of them in order to update those systems as well. I have an 8 hour downtime window, and currently merging the databases takes ~3 hours, and a whole hour of that time is spent creating these ids.
If in the future you do not need to update old_student_id column then you can use virtual columns on PostgreSQL.
CREATE TABLE table2 (
id serial4 NOT NULL,
val1 int4 NULL,
val2 int4 NULL,
total int4 NULL GENERATED ALWAYS AS (id) STORED
);
During the inserting process, the total field will be set to the same value as the id field. But you can not update this field, because this is a virtual column.
Alternative method is a using triggers. In this case you can update your fields. See this example:
Firstly we need create trigger function which will be called before table inserting.
CREATE OR REPLACE FUNCTION table2_insert()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
begin
new.total = new.val1 * new.val2;
return new;
END;
$function$
;
After then:
CREATE TABLE table2 (
id serial4 NOT NULL,
val1 int4 NULL,
val2 int4 NULL,
total int4 NULL
);
create trigger my_trigger before
insert
on
table2 for each row execute function table2_insert();
With both methods, you don't have to update many records every time.
how can i detach a primary key of table from a sequence with out having to drop the table
With "detach" you mean probably, removing the default for the column to the next value of the sequence.
For example, say you have a table definition like this:
Column | Type | Modifiers
------------+---------+----------------------------------------------------------------
yourcolumn | integer | not null default nextval('yourtable_yourcolumn_seq'::regclass)
you want to remove this part: default nextval('yourtable_yourcolumn_seq'::regclass)
If so, you can do it with this statement:
ALTER TABLE yourtable ALTER COLUMN yourcolumn DROP DEFAULT;
I had created a new table named USERLOG with two fields from a previous VIEW. The table already consist of about 9000 records. The two fields taken from the VIEW, i.e. weblog_views consist of IP (consists of IP address), and WEB_LINK (consists of URL). This is the code I used,
CREATE TABLE USERLOG
AS
SELECT C_IP, WEB_LINK FROM weblog_views;
I want to add another column to this table called the USER_ID, which would consists of a sequence starting with 1 to 9000 records to create a unique id for each existing rows. I need help with this part. I'm using Oracle SQL Developer: ODMiner version 3.0.04.
I tried using the AUTO-INCREMENT option,
ALTER TABLE USERLOG
ADD USER_ID INT UNSIGNED NOT NULL AUTO_INCREMENT;
But I get an error with this,
Error report:
SQL Error: ORA-01735: invalid ALTER TABLE option
01735. 00000 - "invalid ALTER TABLE option"
So, I would really appreciate any help that I can get!
You would need to add a column
ALTER TABLE userlog
ADD( user_id number );
create a sequence
CREATE SEQUENCE user_id_seq
START WITH 1
INCREMENT BY 1
CACHE 20;
Update the data in the table
UPDATE userlog
SET user_id = user_id_seq.nextval
Assuming that you want user_id to be the primary key, you would then add the primary key constraint
ALTER TABLE userlog
ADD CONSTRAINT pk_user_id PRIMARY KEY( user_id );
If you want to use the sequence to automatically add the user_id when you do an INSERT (the other option would be to specifically reference user_id_seq.nextval in your INSERT statements, you would also need a trigger
CREATE OR REPLACE TRIGGER trg_userlog_user_id
BEFORE INSERT ON userlog
FOR EACH ROW
BEGIN
:new.user_id := user_id_seq.nextval;
END;
In addition to Justin's excellent answer you might want to prevent NULL values for your user_id in the future (as they could still be caused by UPDATE statements). Therefore, execute the following statement at the end:
ALTER TABLE userlog MODIFY(user_id number NOT NULL);
Step 1.
Create sequence to be used by the column
eg:
CREATE SEQUENCE user_id_seq
START WITH 1
INCREMENT BY 1
CACHE 20;
Step 2.
Update new column with sequence
eg:
UPDATE userlog
SET user_id = user_id_seq.nextval;
Step 3. - Set Sequence as the default value for the column, will work only above Oracle 12c
ALTER TABLE USERLOG
MODIFY USER_ID INT DEFAULT user_id_seq.nextval;