如何确定序列是否在此会话中初始化?

时间:2014-06-12 10:48:56

标签: postgresql session sequence

我需要读取函数中序列的当前值。但是,在每个会话中我第一次尝试使用currval(),我得到以下错误:

currval of sequence "foo_seq" is not yet defined in this session

提示那些可能通过Google搜索此错误找到此问题的人:您需要通过nextval() or setval()初始化每个会话的序列。

我可以使用类似lastval()甚至setval('your_table_id_seq', (SELECT MAX(id) FROM your_table));的内容,但这似乎要么容易出现间隙,要么比简单currval()慢。我的目标是避免间隙和不一致(我知道一些值将手动添加),因此在逻辑处理它们之前使用nextval()并不适合我的目的。我还是需要这个来初始化会话的序列,但我更喜欢这样做:

--start of the function here
IF is_not_initialized THEN
  SELECT setval('foo_seq', (SELECT MAX(id) FROM bar_table)) INTO _current;
ELSE
  SELECT currval('foo_seq') INTO _current;
END IF; 
--some magic with the _current variable and nextvalue() on the right position

重点是我不知道怎么可能" is_not_initialized"看起来是否可能。是否有任何功能或其他技巧?

编辑:实际上,我的计划是让每组客户在正确的序列,完全没有序列和奇怪的"类似序列之类的东西之间进行选择。我现在要求了。即使客户想要这样一个奇怪的序列,它也只能用于需要它的列 - 通常是因为有一些模拟数据,我们需要将它们的密钥(通常几乎无间隙的序列)存储到DB中以便向后兼容。

无论如何,你是对的,这不是正确的解决方案,并且在这些情况下没有任何顺序可能比这种凌乱的解决方案更好,所以我会再次思考(并与客户讨论)是否真的需要它。

2 个答案:

答案 0 :(得分:4)

  

我的目标是避免差距和不一致

如果您想避免间隙,则无法使用序列。如果你想手动分配一些值,也不能合理地使用序列。

你采取的方法是不健全的。不起作用。忘记它,它不会做你认为它会做的事情。

我刚刚在几天前为某人编写了一个简单的无间隙序列生成器的示例实现,并且有一个更完整的in this question

您需要了解,与真正的序列不同,无间隙序列是事务性的。结果是只有一个正在运行的事务可以具有未提交的ID。如果100个并发事务尝试获取ID,则其中只有一个实际获取ID。其他人将不得不等到那个人提交或回滚。因此,它们对于并发性很糟糕,特别是如果与长时间运行的事务相结合。如果您使用多个不同的无间隙序列,并且不同的事务可能以不同的顺序访问它们,它们也可能导致死锁。

仔细想想你是否真的需要这个。

阅读:PostgreSQL gapless sequences

答案 1 :(得分:4)

Craig,a_horse和pozs提供的信息可以帮助您理解使用序列的原则。除了你将如何使用它之外,这里有一个函数,如果它已被初始化,则返回序列的当前值,否则返回null。

如果序列seq尚未初始化,则currval(seq)会因sqlstate 55000.

而引发异常
create or replace function current_seq_value(seq regclass)
returns integer language plpgsql 
as $$
begin
    begin
        return (select currval(seq));
    exception
        when sqlstate '55000' then return null;
    end;
end $$;

select current_seq_value('my_table_id_seq')