如何在 Postgres 中创建相当于 SQL 服务器的标识列

How to create the equivalent of an SQL Server's identity column in Postgres

有一个应用程序使用 MSSQL 作为其后端。现在我正在开发代码,以便它可以使用 PostgreSQL。除了执行时有一点不同外,我几乎完成了它:

保存新应用程序时,

SQL 服务器代码:

create table tower 
(
  npages integer, 
  ifnds integer, 
  ifnid integer, 
  name varchar(20), 
  towid integer not null IDENTITY
)

PostgreSQL 代码:

create table tower 
(
  npages integer, 
  ifnds integer, 
  ifnid integer, 
  name varchar(20)
)

为什么在通过 PostgreSQL 执行时不会自动生成 towid 字段(默认字段)?

有什么可能的原因吗?触发器?程序?

PostgreSQL 将完全按照您的要求创建 table。它不会自动生成一些列(几乎,但这是低级的)。您需要在请求中添加 towid serial primary key

tl;博士

现在在 Postgres 10 中,根据 SQL 标准指定 GENERATED BY DEFAULT AS IDENTITY

create table tower 
(
  npages integer, 
  ifnds integer, 
  ifnid integer, 
  name varchar(20), 
  towid integer GENERATED BY DEFAULT AS IDENTITY    -- per SQL standard
)

标识列

Postgres 10 现在支持 identity column 的概念,并使用标准的 SQL 语法。虽然我不是 MS SQL 服务器方面的专家,但我相信这个新标准支持是等效的。

GENERATED … AS IDENTITY

CREATE TABLE 期间使用的 GENERATED … AS IDENTITY 命令创建了一个隐式序列。与 SERIAL 不同,该序列的创建、命名、权限和删除对您来说都是透明的。现在非常直观。如果您授予 table 使用权限,他们将获得序列的权限。如果删除 table,序列将自动删除。

两种标准语法。仅当您传递一个值而不是让一个值生成时,差异才有意义。通常,人们总是依赖于生成的值,所以通常你会简单地使用第一个版本,GENERATED BY DEFAULT AS IDENTITY.

  • GENERATED BY DEFAULT AS IDENTITY
    • 生成一个值,除非 INSERT 命令提供一个值。
  • GENERATED ALWAYS AS IDENTITY
    • 忽略 INSERT 提供的任何值,除非指定 OVERRIDING SYSTEM VALUE

有关文档,请参阅 CREATE TABLE 页面。

阅读 Peter Eisentraut 的 this interesting page。他用 SERIAL 解释了一些奇怪的问题。新的标识列功能没有此类问题。所以没有理由再使用 SERIAL,没有缺点,只有优点; SERIALGENERATED … AS IDENTITY 取代。

请注意,标识列不一定是主键,也不会自动建立索引。因此,如果这是您的意图,您仍然需要明确指定 PRIMARY KEY(通常是这种情况)。

CREATE TABLE person_ (

    id_ 
        INTEGER 
        GENERATED BY DEFAULT AS IDENTITY   -- Replaces SERIAL. Implicitly creates a SEQUENCE, specified as DEFAULT.
        PRIMARY KEY                        -- Creates index. Specifies UNIQUE. Marks column for relationships.
        ,

    name_ 
        VARCHAR( 80 )

) ;

目的是向您隐藏内部实施细节。您无需知道在幕后生成的序列的名称。例如,您可以在不知道底层顺序的情况下通过列重置计数器。

ALTER TABLE person_ 
    ALTER COLUMN id_ 
    RESTART WITH 1000      -- Reset sequence implicitly, without a name.
;

隐式指定身份:

  • 标记列NOT NULL
  • 创建一个序列
    • 序列类型与列匹配(32 位 64 位等)
  • 将序列与列联系起来
    • 继承权限
    • 级联下降
    • 即使列已重命名,仍与该列相关联
  • 将序列指定为该列的默认值来源

身份列可以采用与CREATE SEQUENCE相同的选项:

  • START WITH start
  • MINVALUE minvalue | NO MINVALUE
  • MAXVALUE maxvalue | NO MAXVALUE
  • INCREMENT [ BY ] increment
  • CYCLE | NO CYCLE
  • CACHE缓存
  • OWNED BY NONE
    (为标识列指定所有权对我来说毫无意义,因为所有权是自动管理的)

愚蠢的选项示例:

id_ INTEGER 
GENERATED BY DEFAULT AS IDENTITY ( 
    START WITH 200 
    MINVALUE 100 
    MAXVALUE 205 
    CYCLE 
    INCREMENT BY 3 
) PRIMARY KEY

添加 4 行:

200

203

100

103