Formas sin SQL dinámico
No hay conversión de números hexadecimales en text
representación a un tipo numérico, pero podemos usar bit(n)
como punto de ruta. Hay indocumentados conversiones desde cadenas de bits (bit(n)
) a tipos enteros (int2
, int4
, int8
) - la representación interna es compatible binaria. Citando a Tom Lane:
Esto se basa en un comportamiento no documentado del convertidor de entrada de tipo bit, pero no veo ninguna razón para esperar que se rompa. Un problema posiblemente más grande es que requiere PG>=8.3 ya que no había un textto bit cast antes de eso.
integer
para máx. 8 dígitos hexadecimales
Se pueden convertir hasta 8 dígitos hexadecimales a bit(32)
y luego obligado a integer
(entero estándar de 4 bytes):
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 usa un tipo entero con signo, por lo que los números hexadecimales por encima de '7fffffff'
desbordamiento en entero negativo números. Esta sigue siendo una representación válida y única, pero el significado es diferente. Si eso importa, cambia a bigint
; ver más abajo.
Para más de 8 dígitos hexadecimales, los caracteres menos significativos (exceso a la derecha) se truncan .
4 bits en una cadena de bits codifica 1 dígito hexadecimal . Los números hexadecimales de longitud conocida se pueden convertir al respectivo bit(n)
directamente. Alternativamente, complete los números hexadecimales de longitud desconocida con ceros a la izquierda (0
) como se muestra y convertir a bit(32)
. Ejemplo con 7 dígitos hexadecimales y int
o 8 dígitos y bigint
:
SELECT ('x'|| 'deafbee')::bit(28)::int
, ('x'|| 'deadbeef')::bit(32)::bigint;
int4 | int8
-----------+------------
233503726 | 3735928559
bigint
para máx. 16 dígitos hexadecimales
Se pueden convertir hasta 16 dígitos hexadecimales a bit(64)
y luego obligado a bigint
(int8
, entero de 8 bytes) - desbordándose nuevamente en números negativos en la mitad superior:
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
para máx. 32 dígitos hexadecimales
El uuid
de Postgres el tipo de datos no es un tipo numérico . Pero es el tipo más eficiente en Postgres estándar para almacenar hasta 32 dígitos hexadecimales, ocupando solo 16 bytes de almacenamiento. Hay un reparto directo de text
a uuid
(sin necesidad de bit(n)
como waypoint), pero exactamente Se requieren 32 dígitos hexadecimales.
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
Como puede ver, la salida estándar es una cadena de dígitos hexadecimales con separadores típicos para UUID.
hash md5
Esto es particularmente útil para almacenar hashes md5 :
SELECT md5('Store hash for long string, maybe for index?')::uuid AS md5_hash;
md5_hash
--------------------------------------
02e10e94-e895-616e-8e23-bb7f8025da42
Ver:
- ¿Cuál es el tipo de datos óptimo para un campo MD5?