Как проверить, являются ли строки 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;