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

时间:2018-04-06 07:08:42

标签: postgresql sequence primary-key auto-increment

我在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);

4 个答案:

答案 0 :(得分:3)

<强>更新

我认为对您而言:当您select last_value时 - 您获得上次使用的序列值,当您insert行时,{{1}的默认值}是id,它将值滚动一个......

<强>前 我相信你在中间步骤中有一个额外的nextval。如果你在一个声明中这样做,它会按预期工作,例如:

nextval

<强> UPDATE2 正如Nick Barnes所注意到的那样,进一步(然后是initial1)迭代会给出错误的结果,你需要使用heis建议的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) 逻辑

答案 1 :(得分:2)

这是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,那么您需要使用triggerUPDATE生成它,一旦您知道了什么id是。

但根据我的经验,最好避免数据和密钥之间存在任何依赖关系。如果您只需要一个独特的filename,我就会创建一个独立的filename_seq

答案 2 :(得分:1)

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

答案 3 :(得分:1)

为避免数据与密钥之间存在任何依赖关系,请尝试:

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