Автоматизация, Программирование

Регистрозависимый поиск в SQL

Время прочтения: 2 мин.

В рамках работы над проектом одна из задач заключалась в том, что из огромного массива необходимо было выбрать карты с определённым кодом. Коды карт могут иметь значения как символы типа ‘+’ или ‘0’, так и символы — буквы алфавита, в том числе строчные и прописные. При работе с кодами карт в виде цифр и спецсимволов проблем не возникло, НО. В процессе работы с кодами карт в виде символов — букв алфавита разного регистра мы столкнулись с проблемой. Наш простой запрос выдавал нам все данные, независимо от регистра: 

  select card, code, value
from table.produkt_code 
where code ='m' 

итог:

cardcodevalue
Card1mстрочная
Card2MПРОПИСНАЯ
Card3mстрочная
Card4mстрочная

Кто и почему не понимает нас?

Оказалось, что на нашем сервере установлены параметры сортировки без учёта регистра.

Я нашла несколько способов решения и хочу поделиться с вами:

Первый способ.

Использование функции ASCII, которая возвращает числовой код крайнего левого символа строкового выражения, являющегося аргументом функции.

Синтаксис функции ASCII( single_character ).

Например, if ASCII(code)=ASCII(‘m’) is TRUE – значение нашего аргумента строчное;

Второй способ.

Мы можем написать запрос сравнения с учетом регистра изменив регистр нашего аргумента и используя COLLATE:

 select 
   code,
   code_reg= case
   when 
   code= UPPER(code) collate Latin1_General_CS_AI 
   then 'UPPER'
   else  'LOWER'
   end
from table.produkt_code

Третий способ.

Функция Unicode, которая возвращает юникод первого значения.

Синтаксис функции: UNICODE (<строковое выражение>).

Возможны варианты использования значений юникодов:

Мы можем создать таблицу- справочник юникодов наших кодов продуктов;

  select unicode(substring('Y',1,1)) Y
  , unicode(substring('y',1,1)) y
  , unicode(substring('F',1,1)) F
  , unicode(substring('f',1,1)) f
  , unicode(substring('M',1,1)) M
  , unicode(substring('m',1,1)) m
  , unicode(substring('P',1,1)) P
  , unicode(substring('p',1,1)) p
  , unicode(substring('R',1,1)) R
  , unicode(substring('r',1,1)) r
  , unicode(substring('D',1,1)) D
  , unicode(substring('d',1,1)) d
  Into table.product_spr

Получим значения юникодов наших аргументов:

YyFfMmPpRrDd
891217010277109801128211468100

либо вычислить юникод изменив регистр нашего аргумента и сравнить с юникодом нашего аргумента;

select 
   code, code_reg= case 
     when unicode(upper(code))= unicode(code)
      then 'UPPER'
      else 'LOWER'
     end
from table.produkt_code

В результате получим информацию о регистре значения кода для дальнейшего анализа и использования в запросе.

codecode_reg
QUPPER
HUPPER
mLOWER
JUPPER
SUPPER
YUPPER
KUPPER
MUPPER

ещё один путь- сразу в коде сравнивать вычисляемое значение с уже известным нам числовым, если их немного и это не трудоёмко.

if Unicode(code)=109 then ‘m-строчная’
if Unicode(code)=77 then ‘M-ПРОПИСНАЯ’

Именно этот вариант я применила в своей работе, т.к. количество необходимых символов для сравнения было невелико.

Думаю, что предпочтительный вариант каждый определит для себя исходя из специфики задачи и, не исключено, что найдутся другие пути решения, ведь SQL –язык многогранный.  Надеюсь, мой опыт будет полезен в работе.

Советуем почитать