我正在从MariaDB切换到Postgres,并遇到了一个小问题。有时我需要在进行INSERT之前建立下一个AUTO_INCREMENT值。这是因为INSERT对其他一些表有影响,如果在INSERT本身后完成修复将非常麻烦。在mySQL / MariaDB中,这很简单。我只是做了
"SELECT AUTO_INCREMENT
FROM information_schema.tables
WHERE table_name = 'users'
AND table_schema = DATABASE( ) ;";
并使用返回的值在进行实际INSERT之前预先校正其他表。我知道使用pgSQL可以将RETURNING
用于SELECT,INSERT和UPDATE语句。但是,这需要对其他表进行INSERT后更正,这反过来会涉及破坏已经过测试并证明有效的代码。我想有一种方法可以找到下一个AUTO_INCREMENT,但我一直无法找到它。除了其他事情,我尝试nextval('users_id_seq')
没有做任何有用的事情。希望有人能够提供帮助。
要将我的原始MariaDB架构移植到Postgres,我使用MariaDB版本编辑了Adminer发出的SQL,以确保它与Postgres一起使用。这主要涉及将INT(11)更改为INTEGER,TINYINT(3)更改为SMALL INT,VARCHAR更改为CHARACTER VARYING等。使用自动增量列,我读了一下并得出结论我需要使用SERIAL。因此,我给Postgres提供的典型SQL就是这样的
CREATE TABLE "users"
(
"id" SERIAL NOT NULL,
"bid" INTEGER NOT NULL DEFAULT 0,
"gid" INTEGER NOT NULL DEFAULT 0,
"sid" INTEGER NOT NULL DEFAULT 0,
"s1" character varying(64)NOT NULL,
"s2" character varying(64)NOT NULL,
"name" character varying(64)NOT NULL,
"apik" character varying(128)NOT NULL,
"email" character varying(192)NOT NULL,
"gsm" character varying(64)NOT NULL,
"rights" character varying(64)NOT NULL,
"managed" character varying(256)NOT NULL DEFAULT
'M_BepHJXALYpLyOjHxVGWJnlAMqxv0KNENmcYA,,',
"senior" SMALLINT NOT NULL DEFAULT 0,
"refs" INTEGER NOT NULL DEFAULT 0,
"verified" SMALLINT NOT NULL DEFAULT 0,
"vkey" character varying(64)NOT NULL,
"lang" SMALLINT NOT NULL DEFAULT 0,
"leader" INTEGER NOT NULL
);
Adminer的这个SQL运行正常。但是,当我尝试让Adminer导出Postgres中的新users
表时,它给了我
CREATE TABLE "public"."users"
(
"id" integer DEFAULT nextval('users_id_seq') NOT NULL,
"bid" integer DEFAULT 0 NOT NULL,
在移植AUTO_INCREMENT列时,我可能会错误地解决问题 - 在这种情况下仍有时间纠正错误。
答案 0 :(得分:2)
As documented in the manual serial
不是“真正的”数据类型,它只是从列中获取默认值的列的快捷方式。
如果在插入之前需要在代码中生成值,请使用nextval()
,然后使用insert语句中的值:
在PL / pgSQL中,这将类似于以下内容。确切的语法显然取决于您使用的编程语言:
declare
l_userid integer;
begin
l_userid := nextval('users_id_seq');
-- do something with that value
insert into users (id, ...)
values (l_userid, ...);
end;
重要的是,永远不会将值传递给序列生成的不的插入语句。 Postgres不会自动将序列值与“手动”提供的值同步。
答案 1 :(得分:0)
如果您在列定义中使用了serial
,那么您在表的同一名称空间中有一个名为TABLE_COLUMN_seq
的序列(其中TABLE
和COLUMN
分别位于表和列的名称)。你可以这样做:
SELECT nextval('TABLE_COLUMN_seq');
我看到你试过了,你能否展示你的CREATE TABLE
声明,以便我们检查所有名字是否合适?
答案 2 :(得分:0)
您可以从序列本身中选择last_value+1
,例如:
t=# create table so109(i serial,n int);
CREATE TABLE
Time: 2.585 ms
t=# insert into so109(n) select i from generate_series(1,22,1) i;
INSERT 0 22
Time: 1.236 ms
t=# select * from so109_i_seq ;
sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called
---------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+-----------
so109_i_seq | 22 | 1 | 1 | 9223372036854775807 | 1 | 1 | 11 | f | t
(1 row)
或使用currval
,例如:
t=# select currval('so109_i_seq')+1;
?column?
----------
23
(1 row)
<强>更新强>
虽然这个答案给出了如何确定Postgres中INSERT之前的下一个auto_increment值(这是标题)的想法,但是提出的方法不适合发布本身的需要。如果您正在寻找&#34;替换&#34;对于RETURNING
语句中的INSERT
指令,更好的方法实际上是&#34;保留&#34; nextval
的值,就像@fog建议的那样。因此,并发事务不会两次获得相同的值......