Есть способы без динамического SQL .
Макс.8 шестнадцатеричных цифр
В представлении text
к числовому типу нет преобразования из шестнадцатеричных чисел, но мы можем использовать bit(n)
в качестве путевой точки. 4 бита в битовой строке кодируют 1 шестнадцатеричную цифру.Существует недокументированное приведение от битовых строк до bit(32)
(макс. 8 шестнадцатеричных цифр) до integer
(стандартное 4-байтовое целое число) - внутреннее представление двоично-совместимо.
SELECT <b>('x' || lpad(hex, 8, '0'))::bit(32)::int</b> AS int_val
FROM (
VALUES ('1'::text)
,('f')
,('100')
,('7fffffff')
,('80000000')
,('deadbeef')
,('ffffffff')
) AS t(hex);
Результат:
int_val
------------
1
15
256
2147483647
-2147483648
-559038737
-1
4 байта достаточно для кодирования всех шестнадцатеричных чисел до 8 цифр, но integer
в Postgres является типом со знакомпоэтому шестнадцатеричные числа выше '7fffffff'
переполняются до отрицательного целого числа .Это все еще уникальное представление, но означает другое.Если это имеет значение, переключитесь на bigint
, см. Ниже.
Для шестнадцатеричных чисел неизвестных различной длины нам нужно дополнить ведущими нулями 0
, как показано на приведениедо bit(32)
.Для чисел известной длины мы можем просто адаптировать спецификатор длины.Пример с 7 шестнадцатеричными цифрами и int
или 8 цифрами и bigint
:
SELECT ('x'|| 'deafbee')::bit(28)::int
, ('x'|| 'deadbeef')::bit(32)::bigint;
int4 | int8
-----------+------------
233503726 | 3735928559
Макс.16 шестнадцатеричных цифр
Используйте bigint
(int8
, 8-байтовое целое) для 16 шестнадцатеричных цифр - переполнение отрицательными числами в верхней половине:
SELECT <b>('x' || lpad(hex, 16, '0'))::bit(64)::bigint</b> AS int8_val
FROM (
VALUES ('ff'::text)
, ('7fffffff')
, ('80000000')
, ('deadbeef')
, ('7fffffffffffffff')
, ('8000000000000000')
, ('ffffffffffffffff')
, ('ffffffffffffffff123') -- too long
) t(hex);
Результат:
int8_val
---------------------
255
2147483647
2147483648
3735928559
9223372036854775807
-9223372036854775808
-1
-1
Для более чем 16 шестнадцатеричных цифр младшие значащие символы (слева направо) получают усеченные .
Это приведение основано на недокументированном поведении , цитирую Тома Лейна здесь :
Это зависит от недокументированного поведения входного преобразователя битового типаНо я не вижу причин ожидать, что это сломается.Возможно, более серьезная проблема заключается в том, что для этого требуется PG> = 8,3, поскольку до этого не было текста, который должен быть приведен к битам.
UUID для макс.32 шестнадцатеричных числа
Тип данных Postgres uuid
равен , а не числовому типу , поэтому это отличается от заданного вопроса.Но это самый эффективный тип в стандартных Postgres для хранения до 32 шестнадцатеричных цифр, занимающих всего 16 байтов.Существует прямое приведение , но требуется точно 32 шестнадцатеричные цифры.
SELECT <b>lpad(hex, 32, '0')::uuid</b> 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
Это особенно полезно для хранения хешей md5 :
SELECT md5('Store hash for long string, maybe for index?')::uuid AS md5_hash
Результат:
md5_hash
--------------------------------------
02e10e94-e895-616e-8e23-bb7f8025da42