为什么PostgreSQL中没有无符号整数?

Adr*_*Hoe 98 postgresql unsigned-integer

我遇到过这篇文章(在MySQL中,tinyint,smallint,mediumint,bigint和int之间的区别是什么?)并且意识到PostgreSQL不支持无符号整数.

任何人都可以帮忙解释为什么会如此?

大多数时候,我使用无符号整数作为MySQL中的自动递增主键.在这样的设计中,当我将数据库从MySQL移植到PostgreSQL时,如何克服这个问题呢?

谢谢.

Pet*_*aut 74

它不符合SQL标准,因此实现它的一般要求较低.

具有太多不同的整数类型会使类型分辨率系统更加脆弱,因此在混合中添加更多类型会有一些阻力.

也就是说,没有理由不能这样做.这只是很多工作.

  • 这个问题很受欢迎,我已经开始修复它:https://github.com/petere/pguint (29认同)

小智 38

已经回答了postgresql缺少无符号类型的原因.但是,我建议将域用于无符号类型.

http://www.postgresql.org/docs/9.4/static/sql-createdomain.html

 CREATE DOMAIN name [ AS ] data_type
    [ COLLATE collation ]
    [ DEFAULT expression ]
    [ constraint [ ... ] ]
 where constraint is:
 [ CONSTRAINT constraint_name ]
 { NOT NULL | NULL | CHECK (expression) }
Run Code Online (Sandbox Code Playgroud)

域就像一个类型,但有一个额外的约束.

您可以使用具体示例

CREATE DOMAIN uint2 AS int4
   CHECK(VALUE >= 0 AND VALUE < 65536);
Run Code Online (Sandbox Code Playgroud)

这是我尝试滥用类型时psql给出的内容.

DS1 = #select(346346 :: uint2);

错误:域uint2的值违反了检查约束"uint2_check"

  • 但我想每次我们想要一个无符号列时使用这个域都会在插入/更新上产生开销。最好在真正有必要(这种情况很少见)的地方使用它,并且习惯于数据类型没有设置我们想要的下限的想法。毕竟,它还设置了一个上限,从逻辑角度来看,这通常是没有意义的。数字类型并不是为了强制我们的应用程序限制而设计的。 (5认同)
  • 这种方法的唯一问题是您“浪费”了 15 位未使用的数据存储。更不用说检查还损失了一些效率。更好的解决方案是 Postgres 将 unsigned 添加为第一类类型。在包含 2000 万条记录且具有这样的索引字段的表中,您在未使用的位上浪费了 40MB 的空间。如果您在另外 20 个表中滥用该空间,那么您现在就浪费了 800MB 的空间。 (4认同)

Tri*_*Man 30

您可以使用CHECK约束,例如:

CREATE TABLE products (
    product_no integer,
    name text,
    price numeric CHECK (price > 0)
);
Run Code Online (Sandbox Code Playgroud)

PostgreSQL也有自动增量smallserialserial类型.

  • 这并不能提供与 unsigned int 相同的分辨率。这意味着无符号整数可以达到“2^32-1”,同时有符号整数可以达到“2^31-1”。 (4认同)
  • 值得一提的是,使用CHECK的列中不能包含任何NULL。 (2认同)
  • @Minutis你确定你不能让x IS NULL OR x BETWEEN 4 AND 40 (2认同)
  • NULL和CHECK是完全正交的。您可以具有“ NULL” /“ NOT NULL”列,带有或不带有“ CHECK”。请注意,根据https://www.postgresql.org/docs/9.4/ddl-constraints.html上的文档,返回空值的`CHECK`计算为TRUE,因此,如果您真的想防止NULL,请使用`而不是NOT NULL(或在“ CHECK”之外)。 (2认同)

Gun*_*dow 15

关于 DOMAINS 的讨论很有趣,但与该问题的唯一可能来源无关。无符号整数的愿望是将具有相同位数的整数范围加倍,这是一个效率参数,而不是排除负数的愿望,每个人都知道如何添加检查约束。

有人问起此事时,Tome Lane 说:

基本上,这种情况发生的可能性为零,除非您能找到一种方法将它们放入不会破坏许多现有应用程序的数字提升层次结构中。如果没记错的话,我们已经不止一次地研究过这个问题,但未能提出一个似乎没有违反 POLA 的可行设计。

什么是“POLA”?Google 给了我 10 个毫无意义的结果。不确定这是否是政治上不正确的想法,因此被审查。为什么这个搜索词不会产生任何结果?任何。

您可以将无符号整数实现为扩展类型而不会太麻烦。如果你用 C 函数来做,那么根本不会有性能损失。您不需要扩展解析器来处理文字,因为 PgSQL 有一种将字符串解释为文字的简单方法,只需将 '4294966272'::uint4 写为您的文字。演员也不应该是一个大问题。您甚至不需要进行范围异常,您只需将 '4294966273'::uint4::int 的语义视为 -1024。或者你可以抛出一个错误。

如果我想要这个,我会做到的。但是因为我在 SQL 的另一边使用 Java,对我来说它没有什么价值,因为 Java 也没有那些无符号整数。所以我一无所获。如果我从 bigint 列中得到一个 BigInteger,而当它应该适合 long 时,我已经很生气了。

另一件事,如果我确实需要存储 32 位或 64 位类型,我可以分别使用 PostgreSQL int4 或 int8,只要记住自然顺序或算术不会可靠地工作。但是存储和检索不受此影响。


下面是我如何实现一个简单的 unsigned int8:

首先我会用

CREATE TYPE name (
    INPUT = uint8_in,
    OUTPUT = uint8_out
    [, RECEIVE = uint8_receive ]
    [, SEND = uint8_send ]
    [, ANALYZE = uint8_analyze ]
    , INTERNALLENGTH = 8
    , PASSEDBYVALUE ]
    , ALIGNMENT = 8
    , STORAGE = plain
    , CATEGORY = N
    , PREFERRED = false
    , DEFAULT = null
)
Run Code Online (Sandbox Code Playgroud)

最小的 2 个函数uint8_inuint8_out我必须首先定义。

CREATE FUNCTION uint8_in(cstring)
    RETURNS uint8
    AS 'uint8_funcs'
    LANGUAGE C IMMUTABLE STRICT;

CREATE FUNCTION uint64_out(complex)
    RETURNS cstring
    AS 'uint8_funcs'
    LANGUAGE C IMMUTABLE STRICT;
Run Code Online (Sandbox Code Playgroud)

需要在 C uint8_funcs.c 中实现它。所以我使用这里的复杂示例并使其变得简单:

PG_FUNCTION_INFO_V1(complex_in);

Datum complex_in(PG_FUNCTION_ARGS) {
    char       *str = PG_GETARG_CSTRING(0);
    uint64_t   result;

    if(sscanf(str, "%llx" , &result) != 1)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                 errmsg("invalid input syntax for uint8: \"%s\"", str)));

    return (Datum)SET_8_BYTES(result);
}
Run Code Online (Sandbox Code Playgroud)

嗯,或者你可以发现它已经完成了

  • 我猜 POLA 就是“最小惊讶原则”。它表明这种变化有可能以意想不到的方式改变现有的行为。 (3认同)