Postgres 序列的last_value 字段无法按预期工作

问题描述 投票:0回答:5

我在 postgres 中有一个表,其主键是使用序列分配的(我们称之为“a_seq”)。该序列用于递增值并将当前值作为要插入的记录的主键插入。

我用于序列的代码:

CREATE SEQUENCE public.a_seq
    INCREMENT 1
    START 1
    MINVALUE 1
    MAXVALUE 9223372036854775807
    CACHE 1;

ALTER SEQUENCE public.AssembleTable_RowId_seq OWNER TO postgres;

我正在尝试从磁盘复制文件并将有关复制文件的信息插入到表中。磁盘中有相同名称的文件,因此我使用此查询从序列中检索“last_value”:

SELECT last_value FROM a_seq;

并重命名文件“_”,然后将其插入数据库,以便该文件的文件名和主键(id)一致,例如:

id | fileName                         
1  | 1_asd.txt

但是当我插入记录时,id 始终比从查询中获取的“last_value”大 1 个值,因此表如下所示:

id | fileName                         
2  | 1_asd.txt

我尝试多次执行上面的选择查询来检查它是否增加了值,但事实并非如此。
知道如何在插入之前获取分配给记录的值吗?

注意:我使用 MATLAB,这是用于插入的代码:

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);
postgresql sequence primary-key auto-increment
5个回答
4
投票

更新了

我相信你会发生的是:当你

select last_value
- 你得到最后使用的序列值并且当你
insert
行时,
id
的默认值是
nextval
,它将值滚动到上面1。 ..

上一个 我相信你在中间步骤的某个地方有一个额外的

nextval
。如果您在一条语句中执行此操作,它将按您的预期工作,例如:

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)

更新2 正如尼克·巴恩斯(Nick Barnes)注意到的那样,进一步(然后是初始1)迭代将给出错误的结果,所以你需要使用他提出的

CASE
逻辑


4
投票

这是 Postgres 实现序列方式的一个怪癖;作为事务性数据库中本质上的非事务性对象,它们的行为有点奇怪。

第一次在序列上调用

nextvalue()
时,它不会影响您在 a_seq.last_value
 中看到的数字。然而,它会
翻转a_seq.is_called标志:

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

因此,如果您需要序列中的下一个值,您需要类似

SELECT last_value + CASE WHEN is_called THEN 1 ELSE 0 END FROM a_seq

请注意,如果两个进程同时执行此操作,则会严重损坏,因为无法保证您实际上会从下一个 
nextval()

调用中收到此值。在这种情况下,如果您确实需要

filename
来匹配
id
,则需要使用
trigger
生成它,或者在知道 UPDATE 是什么后
id
生成它。

但根据我的经验,最好避免数据和密钥之间的任何依赖关系。如果您需要的只是一个独特的

filename

,我只需创建一个独立的

filename_seq
    


1
投票
INSERT

语句而没有

id
值时 - Postgres 自动使用
next_val
从序列中获取它。变量
colnames
中的列列表没有
id
,因此 PG 从序列中获取下一个值。要解决这个问题,您可以将 id 添加到
colnames
    


1
投票

CREATE SEQUENCE your_sequence INCREMENT 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1; ALTER TABLE your_sequence OWNER TO postgres;



0
投票
select last_value from xscheme.x_seq;

    

© www.soinside.com 2019 - 2024. All rights reserved.