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

时间:2013-12-28 01:44:04

标签: postgresql unsigned-integer

我遇到过这篇文章(What is the difference between tinyint, smallint, mediumint, bigint and int in MySQL?)并意识到PostgreSQL不支持无符号整数。

任何人都可以帮忙解释为什么会这样吗?

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

感谢。

6 个答案:

答案 0 :(得分:65)

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

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

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

答案 1 :(得分:35)

已经回答了为什么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) }

Domain就像一个类型,但有一个额外的约束。

对于具体示例,您可以使用

CREATE DOMAIN uint2 AS int4
   CHECK(VALUE >= 0 AND VALUE < 65536);

以下是我尝试滥用该类型时psql提供的内容。

  

DS1 = #select(346346 :: uint2);

     

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

答案 2 :(得分:26)

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

CREATE TABLE products (
    product_no integer,
    name text,
    price numeric CHECK (price > 0)
);

PostgreSQL还有serialbigserial类型用于自动增量。

答案 3 :(得分:5)

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

asked by someone about it时,托姆·莱恩说:

基本上,除非您能找到,否则发生这种情况的可能性为零 使它们适合数字促销层次结构的方法 破坏很多现有的应用程序。我们对这一点的关注不止 一次,如果内存可用,但无法提出可行的设计 似乎没有违反POLA。

什么是“ POLA”? Google gave me 10 results that are meaningless。不知道这是否是政治错误的想法,因此受到审查。为什么这个搜索词不会产生任何结果?随便。

您可以将无符号整数实现为扩展类型,而不会带来太多麻烦。如果您使用C函数执行此操作,那么几乎不会有任何性能损失。您无需扩展解析器即可处理文字,因为PgSQL具有将字符串解释为文字的简便方法,只需将“ 4294966272” :: uint4编写为文字即可。演员阵容也不是什么大问题。您甚至不需要做范围例外,您可以将'4294966273':: uint4 :: int的语义视为-1024。否则您可以抛出错误。

如果我想要这个,我会做的。但是由于我在SQL的另一端使用Java,因此对我来说意义不大,因为Java也没有这些无符号整数。所以我一无所获。如果从bigint列中获取BigInteger,而现在它应该很长,我已经很烦。

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


这是我可以实现一个简单的无符号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
)

我必须首先定义的最少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;

需要在C uint8_funcs.c中实现此功能。因此,我使用the complex example from here使其变得简单:

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);
}

嗯,还是可以just find it done already

答案 4 :(得分:0)

根据最新文档,支持单个整数,但表中没有无符号整数。但是,串行类型有点类似于无符号,只是它从1开始而不是从0开始。但上限与单数相同。因此,系统确实没有未签名的支持。正如Peter指出的那样,为实现未签名版本打开了大门。根据我使用C编程的经验,可能需要对代码进行大量更新。

https://www.postgresql.org/docs/10/datatype-numeric.html

integer     4 bytes     typical choice for integer  -2147483648 to +2147483647
serial  4 bytes     autoincrementing integer    1 to 2147483647

答案 5 :(得分:0)

Postgres确实具有许多人都不知道的无符号整数类型:OID

  

oid类型当前实现为无符号的四字节整数。 […]

     

oid类型本身只有很少的操作无法比较。有可能   强制转换为整数,然后使用标准   整数运算符。 (当心可能的签名与未签名的混淆   如果这样做的话。)

尽管它不是numeric type,并且尝试对其进行任何算术(甚至是按位运算)都会失败。另外,它只有4个字节(INTEGER),没有相应的8个字节(BIGINT)无符号类型。

因此,自己使用它并不是一个好主意,我也同意所有其他答案,即在Postgresql数据库设计中,您应始终为{{}使用INTEGERBIGINT列3}}主键-让它以负号(MINVALUE开始,或者如果您想用尽整个域,则允许它环绕(CYCLE)。

但是,它对于输入/输出转换非常有用,例如从另一个DBMS进行迁移。将值2147483648插入整数列将导致“ 错误:整数超出范围”,而使用表达式2147483648::OID可以正常工作。
同样,当使用mycolumn::TEXT选择整数列作为文本时,有时会得到负值,而使用mycolumn::OID::TEXT则总是得到自然数。

请参见serial