PostgreSQL auto-increment aren't incremented using COPY - sql

I have the following table in PostgreSQL:
CREATE TABLE cars (id SERIAL PRIMARY KEY,
car_id SERIAL REFERENCES car_models (id) ON DELETE CASCADE);
When using COPY with the following:
COPY cars FROM '/Users/my-user/cars.csv' DELIMITER ',' CSV HEADER;
Containing:
id, car_id
1, 4
2, 3
3, 9
Then my primary key aren't incremented, so calling afterwards:
insert into cars (car_id) values (11)
fails with:
ERROR: duplicate key value violates unique constraint "cars_pkey"
DETAIL: Key (id)=(1) already exists.

It's easy to solve this problem, as below, you can set the start value of the sequence after you copy data into your table (your_now_max_value, for example 123).
alter sequence cars_id_seq restart with your_now_max_value;
The script shell copy_cars.sh maybe has 4 lines as below:
psql -d database -c"copy cars from xx.txt with delimiter ','"
max_id=`psql -d database -c"copy(select max(id) from cars) to stdout"`
max_id=$(($max_id + 1))
psql -d database -c"alter sequence cars_id_seq restart with ${max_id}"
Of course, you can add some alert code to ensure the robustness.Then you can set a scheduler for the script to achieve your aim of twice a month.

There is a flag 'EXPLICIT_IDS' which is used for this purpose.
Try using
COPY cars FROM '/Users/my-user/cars.csv' DELIMITER ',' CSV HEADER EXPLICIT_IDS;
Hope this helps.

Related

H2 Database fails to find existing column

My Configuration file:
# H2
spring.h2.console.enabled=true
spring.h2.console.path=/h2
# Datasource
spring.datasource.url=jdbc:h2:file:~/test
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver
my data.sql script is something like :
CREATE TABLE IF NOT EXISTS people (
ID INT AUTO_INCREMENT NOT NULL PRIMARY KEY,
vname varchar(255) not null
);
INSERT INTO people(vname) VALUES ('Chuck Norris');
When this is executed, INSERT fails with error :
cannot find 'VNAME' column.
Why is the column name auto all capsed? does that affect my INSERT command?
I just created the table, why cant INSERT find vname column?
Did you perhaps already create the table PEOPLE without the VNAME column? Your SQL won't touch it if the table already exists. Remove the database files and try again...

How to set up value for serial type in PostgreSQL? [duplicate]

This question already has answers here:
How to reset Postgres' primary key sequence when it falls out of sync?
(33 answers)
Closed 5 years ago.
I have a primery key in my table as follows:
CREATE TABLE a (
id serial NOT NULL,
valuea citext NOT NULL,
CONSTRAINT a_pkey PRIMARY KEY (id),
);
Table had the following rows:
id value
198 b
199 j
By accident I did this insert
Insert Into a(id,valuea) values (200,'hello');
Now, when I try to do another insert in the correct way:
Insert Into a(valuea) values ('b');
I expect it to insert (201,b) but the serial counter doesn't know 200 has been used because of the last manual insert.
I get:
ERROR: duplicate key value violates unique constraint
"a_pkey" DETAIL: Key (id)=(200) already exists.
I understand this error.. basically it happens because my last insert was not used the Serial and therefore it's counter didn't rise up.
What I don't know is how to fix it?
How do I tell the serial counter to start from 201?
You need to find the sequence name, normally something like <your table>_id_seq and do :
ALTER SEQUENCE a_id_seq INCREMENT BY 1;
When you create a serial key, Postgres creates a sequence that it uses to generate next values.
Just find that sequence and modify its START value to e.g 201 .
SELECT setval(<name of the sequence>, 201, true);

Restoring a Truncated Table from a Backup

I am restoring the data of a truncated table in an Oracle Database from an exported csv file. However, I find that the primary key auto-increments and does not insert the actual values of the primary key constrained column from the backed up file.
I intend to do the following:
1. drop the primary key
2. import the table data
3. add primary key constraints on the required column
Is this a good approach? If not, what is recommended? Thanks.
EDIT: After more investigation, I observed there's a trigger to generate nextval on a sequence to be inserted into the primary key column. This is the source of the predicament. Hence, following the procedure above would not solve the problem. It lies in the trigger (and/or sequence) on the table. This is solved!
easier to use your .csv as an external table and then go
create table your_table_temp as select * from external table
examine the data in the new temp table to ensure you know what range of primary keys is present
do a merge into the new table
samples from here and here
CREATE TABLE countries_ext (
country_code VARCHAR2(5),
country_name VARCHAR2(50),
country_language VARCHAR2(50)
)
ORGANIZATION EXTERNAL (
TYPE ORACLE_LOADER
DEFAULT DIRECTORY ext_tab_data
ACCESS PARAMETERS (
RECORDS DELIMITED BY NEWLINE
FIELDS TERMINATED BY ','
MISSING FIELD VALUES ARE NULL
(
country_code CHAR(5),
country_name CHAR(50),
country_language CHAR(50)
)
)
LOCATION ('Countries1.txt','Countries2.txt')
)
PARALLEL 5
REJECT LIMIT UNLIMITED;
and the merge
MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);
Edit: after you have merged the data you can drop the temp table and the result is your previous table with the old data and the new data together
Edit you mention " During imports, the primary key column does not insert from the file, but auto-increments". This can only happen when there is a trigger on the table, likely, Before insert on each row. Disable the trigger and then do your import. Re-enable the trigger after committing your inserts.
I used the following procedure to solve it:
drop trigger trigger_name
Imported the table data into target table
drop sequence sequence_name
CREATE SEQUENCE SEQ_NAME INCREMENT BY 1 START WITH start_index_for_next_val MAXVALUE max_val MINVALUE 1 NOCYCLECACHE 20 NOORDER
CREATE OR REPLACE TRIGGER "schema_name"."trigger_name"
before insert on target_table
for each row
begin
select seq_name.nextval
into :new.unique_column_name
from dual;
end;

Postgres: Problems using insert with select

I have a table defined like this:
CREATE TABLE wp_master (
gid integer NOT NULL DEFAULT nextval('wp_master_gid_seq'::regclass),
name character varying(80),
....
type integer DEFAULT 4,
CONSTRAINT p_key PRIMARY KEY (gid),
);
I want to insert data into the table from another table so I
insert into wp_master ( name, .... type) select "NAME", ...., 1 from ."Tiri2011";
but I get the error:
ERROR: duplicate key value violates unique constraint "p_key"
DETAIL: Key (gid)=(2) already exists.
Why is postgres trying to put anything into the gid field when I have explicitly not included it in the list of columns? I assumed that gid pick up its value from the sequence.
Russell
Is is trying to insert the next value of the wp_master_gid_seq sequence. Declaring an id column as serial (auto-increment) will create a sequence which has a stored value of the last inserted id which was auto-incremented. If at anytime you inserted a gid value manually, it bypassed the sequence and the autoincrement function may become broken, because the sequence value did not get updated accordingly.
The easiest way to fix it is to change the value of the sequence to the (max gid value of your table) + 1. Just execute this once and you should be ok
select setval('wp_master_gid_seq', coalesce((select max(id)+1 from wp_master), 1), false)

Attach sequence to a column and start with 1000

Apply this sql script:
create table software (
id bigint not null,
name varchar(255),
description varchar(255),
constraint pk_software primary key (id))
;
create sequence software_seq;
Then this one:
alter sequence software_seq start with 1000;;
insert into software (id, name, description) values ( 1, 'Soft1', 'Description1');
Then when insert new software programatically (from java), got new software with id = 24
Why not with 1001? Since 'alter sequence software_seq start with 1000;'
You have a few things wrong here.
First of all, just creating a sequence with a particular name doesn't attach it to the table and column that you want using it. You need to change software.id to use software_seq for default values:
alter table software alter column id set default nextval('software_seq');
and you'll want to change the sequence's ownership too (unless of course you're using the sequence in other places):
OWNED BY table_name.column_name
OWNED BY NONE
The OWNED BY option causes the sequence to be associated with a specific table column, such that if that column (or its whole table) is dropped, the sequence will be automatically dropped as well. If specified, this association replaces any previously specified association for the sequence. The specified table must have the same owner and be in the same schema as the sequence. Specifying OWNED BY NONE removes any existing association, making the sequence "free-standing".
So you should:
alter sequence software_seq owned by software.id;
Then when inserting, you'd either leave out the id:
insert into software (name, description) values ('...', '...');
or specify DEFAULT:
insert into software (id, name, description) values (default, '...', '...');
Your other problem is that start with doesn't do what you think it does:
start
The optional clause START WITH start changes the recorded start value of the sequence. This has no effect on the current sequence value; it simply sets the value that future ALTER SEQUENCE RESTART commands will use.
If you want the sequence to start at 1000 then you can:
alter sequence software_seq restart with 1000;
Alternatively, you could use setval:
select setval('software_seq', 1000);
Of course, you could also use bigserial:
The data types smallserial, serial and bigserial are not true types, but merely a notational convenience for creating unique identifier columns (similar to the AUTO_INCREMENT property supported by some other databases). In the current implementation, specifying:
CREATE TABLE tablename (
colname SERIAL
);
is equivalent to specifying:
CREATE SEQUENCE tablename_colname_seq;
CREATE TABLE tablename (
colname integer NOT NULL DEFAULT nextval('tablename_colname_seq')
);
ALTER SEQUENCE tablename_colname_seq OWNED BY tablename.colname;
So using bigserial as the id column type would set up all the sequence stuff for you. Then you'd set the starting value as before using alter sequence or setval.
Probably I got. If one wants to change the sequence, then he should use this syntax:
ALTER SEQUENCE sequenceName [ RESTART WITH long ] [ INCREMENT BY long ]
i.e. use 'RESTART' but not 'START'
I tested: then it really start with 1000 when inserting new value.