Reputation: 172
I have a table in postgres whose primary key is assinged using a sequence (let's call it 'a_seq'). The sequence is for incrementing the value and inserting the current value as primary key of record being inserted.
Code i use for sequence:
CREATE SEQUENCE public.a_seq
INCREMENT 1
START 1
MINVALUE 1
MAXVALUE 9223372036854775807
CACHE 1;
ALTER SEQUENCE public.AssembleTable_RowId_seq OWNER TO postgres;
I am trying to copy a file from a disk and insert the information about copied file to table. There are files with same name in the disk so i'm retrieving the "last_value" from the sequence with this query:
SELECT last_value FROM a_seq;
and rename file "_" then insert it do database so the file name and the primary key (id) of that file is coherent like:
id | fileName
1 | 1_asd.txt
But when i insert the record, the id is always 1 value greater than the "last_value" a get from the query so table looks like this:
id | fileName
2 | 1_asd.txt
And i've tried to execute the select query above multiple times to check if its increment the value but it doesn't.
Any idea how to get the value which will be assinged to the record before the insertion?
NOTE: I use MATLAB and this is the code is use for insertion:
colnames = {'DataType' , ...
'FilePath' , ...
'FileName' , ...
'FileVersion' , ...
'CRC32Q' , ...
'InsertionDateTime', ...
'DataSource' };
data = {FileLine{5} ,... % DataType
tempPath ,... % FilePath
FileLine{1} ,... % FileName
FileLine{2} ,... % FileVersion
FileLine{3} ,... % CRC32Q
FileLine{4} ,... % InsertionDateTime
FileLine{6} ,... % DataSource};
data_table = cell2table(data, 'VariableNames', colnames);
datainsert(conn , 'CopiedFiles' , colnames , data_table);
Upvotes: 5
Views: 18265
Reputation: 1
looking at what you posted, to select the last_value
of x_seq
you must call it like a table ie:
select last_value from xscheme.x_seq;
Upvotes: -1
Reputation: 21376
This is a quirk in the way Postgres implements sequences; as inherently non-transactional objects in a transactional database, they behave a bit strangely.
The first time you call nextvalue()
on a sequence, it will not affect the number you see in a_seq.last_value
. However, it will flip the a_seq.is_called
flag:
test=# create sequence a_seq;
test=# select last_value, is_called from a_seq;
last_value | is_called
------------+-----------
1 | f
test=# select nextval('a_seq');
nextval
---------
1
test=# select last_value, is_called from a_seq;
last_value | is_called
------------+-----------
1 | t
So if you need the next value in the sequence, you'd want something like
SELECT
last_value + CASE WHEN is_called THEN 1 ELSE 0 END
FROM a_seq
Note that this is horribly broken if two processes are doing this concurrently, as there's no guarantee you'll actually receive this value from your next nextval()
call. In that case, if you really need the filename
to match the id
, you'd need to either generate it with a trigger, or UPDATE
it once you know what the id
is.
But in my experience, it's best to avoid any dependencies between your data and your keys. If all you need is a unique filename
, I'd just create an independent filename_seq
.
Upvotes: 5
Reputation: 51649
updated
What I believe happens for you is: when you select last_value
- you get last used sequence value and when you insert
row, the default value for id
is nextval
, which rolls value by one above...
previous
I believe you have an extra nextval
somewhere in middle step. If you do it in one statement, it works as you expect, eg:
t=# create table so12(s int default nextval('s'), t text);
CREATE TABLE
t=# insert into so12(t) select last_value||'_abc.txt' from s;
INSERT 0 1
t=# select * from so12;
s | t
---+-----------
1 | 1_abc.txt
(1 row)
update2
as Nick Barnes noticed, further (then initial1) iterations will give wrong results, su you need to use heis proposed CASE
logic
Upvotes: 4
Reputation: 570
To avoid any dependencies between your data and your keys, Please try:
CREATE SEQUENCE your_sequence
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 1
CACHE 1;
ALTER TABLE your_sequence
OWNER TO postgres;
Upvotes: 1
Reputation: 1023
When INSERT
statement is executed without a value for id
- Postgres automatically takes it from sequence using next_val
. List of columns in the variable colnames
does not have an id
, so PG takes next value from the sequence. To solve the problem you may add id to colnames
.
Upvotes: 1