我正在尝试使用PostgreSQL 9.1将十六进制转换为十进制
使用此查询:
SELECT to_number('DEADBEEF', 'FMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
我得到以下错误:
ERROR: invalid input syntax for type numeric: " "
我做错了什么?
n6lpvg4x1#
text表示中的十六进制数字不会强制转换为数字类型,但我们可以使用bit(n)作为路点。存在从位串(bit(n))到整数类型(int2、int4、int8)的未记录转换--内部表示是二进制兼容的。Quoting Tom Lane:这依赖于位类型输入转换器的一些未记录的行为,但我认为没有理由期望它会被打破。一个可能更大的问题是,它需要PG>=8.3,因为在此之前没有文本到位强制转换。
text
bit(n)
int2
int4
int8
integer
最多可将8位十六进制数字转换为bit(32),然后强制转换为integer(标准4字节整数):
bit(32)
SELECT ('x' || lpad(hex, 8, '0'))::bit(32)::int AS int_val FROM ( VALUES ('1'::text) , ('f') , ('100') , ('7fffffff') , ('80000000') -- overflow into negative number , ('deadbeef') , ('ffffffff') , ('ffffffff123') -- too long ) AS t(hex);
int_val ------------ 1 15 256 2147483647 -2147483648 -559038737 -1
Postgres使用带符号整数类型,因此'7fffffff'以上的十六进制数会溢出为负整数数。这仍然是一种有效的、唯一的表示,但其含义有所不同。如果这很重要,请切换到bigint;见下文。
'7fffffff'
bigint
对于超过8位的十六进制数字,最低有效字符(超出右侧)将被截断。
位串中的4位编码1个十六进制数字。已知长度的十六进制数可以直接转换为相应的bit(n)。或者,如图所示,用前导零(0)填充未知长度的十六进制数字,并转换为bit(32)。具有7个十六进制数字和int或8个数字和bigint的示例:
0
int
SELECT ('x'|| 'deafbee')::bit(28)::int , ('x'|| 'deadbeef')::bit(32)::bigint;
int4 | int8 -----------+------------ 233503726 | 3735928559
最多16位十六进制数字可以转换为bit(64),然后强制转换为bigint(int8,8字节整数)-再次溢出到上半部分的负数:
bit(64)
SELECT ('x' || lpad(hex, 16, '0'))::bit(64)::bigint AS int8_val FROM ( VALUES ('ff'::text) , ('7fffffff') , ('80000000') , ('deadbeef') , ('7fffffffffffffff') , ('8000000000000000') -- overflow into negative number , ('ffffffffffffffff') , ('ffffffffffffffff123') -- too long ) t(hex);
int8_val --------------------- 255 2147483647 2147483648 3735928559 9223372036854775807 -9223372036854775808 -1 -1
uuid
Postgres uuid数据类型不是数字类型。但它是标准Postgres中存储高达32位十六进制数字的最高效类型,仅占用16字节的存储空间。text到uuid有直接转换(不需要bit(n)作为路点),但需要正好32个十六进制数字。
SELECT lpad(hex, 32, '0')::uuid AS uuid_val FROM ( VALUES ('ff'::text) , ('deadbeef') , ('ffffffffffffffff') , ('ffffffffffffffffffffffffffffffff') , ('ffffffffffffffffffffffffffffffff123') -- too long ) t(hex);
uuid_val -------------------------------------- 00000000-0000-0000-0000-0000000000ff 00000000-0000-0000-0000-0000deadbeef 00000000-0000-0000-ffff-ffffffffffff ffffffff-ffff-ffff-ffff-ffffffffffff ffffffff-ffff-ffff-ffff-ffffffffffff
如您所见,标准输出是一个带有UUID典型分隔符的十六进制数字字符串。
这对于存储MD5哈希特别有用:
SELECT md5('Store hash for long string, maybe for index?')::uuid AS md5_hash;
md5_hash -------------------------------------- 02e10e94-e895-616e-8e23-bb7f8025da42
请参见:
1条答案
按热度按时间n6lpvg4x1#
没有动态SQL的方式
text
表示中的十六进制数字不会强制转换为数字类型,但我们可以使用bit(n)
作为路点。存在从位串(bit(n)
)到整数类型(int2
、int4
、int8
)的未记录转换--内部表示是二进制兼容的。Quoting Tom Lane:这依赖于位类型输入转换器的一些未记录的行为,但我认为没有理由期望它会被打破。一个可能更大的问题是,它需要PG>=8.3,因为在此之前没有文本到位强制转换。
最大为
integer
。8位十六进制数字最多可将8位十六进制数字转换为
bit(32)
,然后强制转换为integer
(标准4字节整数):Postgres使用带符号整数类型,因此
'7fffffff'
以上的十六进制数会溢出为负整数数。这仍然是一种有效的、唯一的表示,但其含义有所不同。如果这很重要,请切换到bigint
;见下文。对于超过8位的十六进制数字,最低有效字符(超出右侧)将被截断。
位串中的4位编码1个十六进制数字。已知长度的十六进制数可以直接转换为相应的
bit(n)
。或者,如图所示,用前导零(0
)填充未知长度的十六进制数字,并转换为bit(32)
。具有7个十六进制数字和int
或8个数字和bigint
的示例:最大值为
bigint
。16位十六进制数字最多16位十六进制数字可以转换为
bit(64)
,然后强制转换为bigint
(int8
,8字节整数)-再次溢出到上半部分的负数:最大为
uuid
。32位十六进制数字Postgres
uuid
数据类型不是数字类型。但它是标准Postgres中存储高达32位十六进制数字的最高效类型,仅占用16字节的存储空间。text
到uuid
有直接转换(不需要bit(n)
作为路点),但需要正好32个十六进制数字。如您所见,标准输出是一个带有UUID典型分隔符的十六进制数字字符串。
MD5哈希
这对于存储MD5哈希特别有用:
请参见: