我遇到过这篇文章(What is the difference between tinyint, smallint, mediumint, bigint and int in MySQL?)并意识到PostgreSQL不支持无符号整数。
任何人都可以帮忙解释为什么会这样吗?
大多数时候,我在MySQL中使用无符号整数作为自动递增的主键。在这样的设计中,当我将数据库从MySQL移植到PostgreSQL时,如何克服这个问题?
感谢。
答案 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还有serial
和bigserial
类型用于自动增量。
答案 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_in
和uint8_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数据库设计中,您应始终为{{}使用INTEGER
或BIGINT
列3}}主键-让它以负号(MINVALUE
开始,或者如果您想用尽整个域,则允许它环绕(CYCLE
)。
但是,它对于输入/输出转换非常有用,例如从另一个DBMS进行迁移。将值2147483648
插入整数列将导致“ 错误:整数超出范围”,而使用表达式2147483648::OID
可以正常工作。
同样,当使用mycolumn::TEXT
选择整数列作为文本时,有时会得到负值,而使用mycolumn::OID::TEXT
则总是得到自然数。
请参见serial。