Как проверить, являются ли строки VARCHAR (не) шестнадцатеричными?

TL;DR Как проверить, является ли строка шестнадцатеричной при выборе строк?


Если бы у меня была таблица с GUID, где некоторые из них были бы Base36 вместо шестнадцатеричного:

  ID | GUID
  ===|=================================
   1 | CAFEBABECAFED00DB16B00B515BADA55
   2 | 0123456789ABCDEFGHIJKLMNOPQRSTUV
   3 | DEADBEAF4D15EA5EDEFEC8EDFEE1DEAD

Я хочу получить все строки с GUID, которые не являются исключительно шестнадцатеричными.

Для одиночки я мог бы попробовать CONVERT(VARBINARY(32),[GUID],2) и посмотреть, не получится ли, но я не могу этого сделать в запросе. Если бы я мог запросить WHERE isNaN(parseInt(GUID,16)), это было бы отказоустойчиво (хотя должно быть применено ко всем строкам).

Конечно, я мог бы полнотекстовый поиск букв после F (WHERE [GUID] LIKE '%g%' OR [GUID] LIKE '%h%' OR …), но этот крайний подход заставил меня задать этот вопрос:

Как запросить только (не)шестнадцатеричные поля?

4 ответа

;WITH rw AS
(
    SELECT '0000AF0012B' ishexornot
    UNION ALL
    SELECT '0000AF0012G'
    UNION ALL
    SELECT '0000AF0012 '
)
SELECT *, CASE WHEN ishexornot LIKE '%[^0-9A-F]%' THEN 0 ELSE 1 END
FROM rw

так

WHERE [GUID] LIKE '%[^0-9A-F]%'

Начиная с SQL Server 2012, вы можете использовать TRY_CONVERT():

declare @t table (
    Id int identity (1,1) primary key,
    Value varchar(100) not null
);

insert into @t (Value)
values
('F6AA1EE0-DF55-43E8-92ED-B2A84E621485'),
('F32E4621CE004C47889DEBDA9BA790AF'),
('09F94C95-9004-4C7C-8F5D-9CA374546288'),
('5DAFD4C7-C780-4F32-9BF1-52027371546A'),
('4D81BD419BFE42EA956E715023EF3B77');

select t.*
from @t t
where try_convert(uniqueidentifier, t.Value, 2) is null;

В отличие от CONVERT() запрос в примере работает без ошибок и возвращает строки 2 и 5.

Просто используйте LIKE с подстановочным знаком для определенного диапазона:

SELECT * FROM [GUIDs] WHERE [GUID] LIKE '%[g-z]%';

В postgres вы можете использовать регулярные выражения POSIX

select "GUID" ~ '[0-9A-F]{32}' as is_hex from the_table;

Вышеупомянутое проверяет, равна ли длина строки 32

Если вы также заботитесь о чувствительности к регистру, то, возможно, потребуется сопоставление.
Поскольку поведение LIKE по умолчанию в большинстве случаев не учитывает регистр.

select Id, [Guid], 
 (CASE WHEN [Guid] collate sql_latin1_general_cp1_cs_as NOT LIKE '%[^0-9A-F]%' THEN 1 ELSE 0 END) as isHex
from (
select 1 as Id, 'CAFEBABECAFED00DB16B00B515BADA55' as [Guid] union all
select 2, '0123456789ABCDEFGHIJKLMNOPQRSTUV' union all
select 3, 'DEADBEAF4D15EA5EDEFEC8EDFEE1DEAD' union all
select 4, 'cafeBABECAFED00DB16B00B515badA55'
) q;
Другие вопросы по тегам