Как лучше всего выбирать строковые поля на основе диапазонов символов?
-
02-07-2019 - |
Вопрос
Мне нужно добавить пользователям моего программного обеспечения возможность выбирать записи по диапазонам символов.
Как я могу написать запрос, который возвращает все виджеты из таблицы, имя которой попадает, например, в диапазон Ba-Bi?
В настоящее время я использую операторы «больше» и «меньше», поэтому приведенный выше пример будет выглядеть так:
select * from widget
where name >= 'ba' and name < 'bj'
Обратите внимание, как я «увеличил» последний символ верхней границы с i на j, чтобы «велосипед» не остался без внимания.
Существует ли общий способ найти следующий символ после заданного символа на основе сопоставления поля или было бы безопаснее создать второе условие?
select * from widget
where name >= 'ba'
and (name < 'bi' or name like 'bi%')
Мое приложение должно поддерживать локализацию.Насколько чувствителен такой запрос к различным наборам символов?
Мне также необходимо поддерживать как MSSQL, так и Oracle.Каковы мои варианты обеспечения игнорирования регистра символов независимо от того, какой язык присутствует в данных?
Решение
Перейдем непосредственно к локализации.Вы бы сказали «аа» >= «ба»?Вероятно, нет, но в Швеции это так.Кроме того, вы просто не можете предполагать, что можете игнорировать регистр в любом языке.Регистр явно зависит от языка, наиболее распространенным примером является турецкий:заглавная буква i — это İ.Строчная буква I — ı.
Теперь ваша база данных SQL определяет результат <, == и т. д. с помощью «порядка сопоставления».Это определенно зависит от языка.Таким образом, вы должны явно контролировать это для каждого запроса.Турецкий порядок сортировки поместит эти i на свои места (на турецком языке).Вы не можете полагаться на параметры сортировки по умолчанию.
Что касается «приращения», не беспокойтесь.Придерживайтесь >= и <=.
Другие советы
Для MSSQL см. эту тему: http://bytes.com/forum/thread483570.html .
Для Oracle это зависит от вашей версии Oracle, поскольку Oracle 10 теперь поддерживает запросы, подобные регулярным выражениям (p): http://www.psoug.org/reference/regexp.html (найдите regexp_like) и посмотрите эту статью: http://www.oracle.com/technology/oramag/webcolumns/2003/techarticles/rischert_regexp_pt1.html
ХТХ
К сожалению, функция подстроки Oracle — это SUBSTR(), а в SQL-Server — SUBSTRING().
Вы можете написать простую оболочку вокруг одного или обоих из них, чтобы они имели одно и то же имя функции + прототип.
Тогда вы можете просто использовать
MY_SUBSTRING(name, 2) >= 'ba' AND MY_SUBSTRING(name, 2) <= 'bi'
или похожие.
Вы могли бы использовать это...
select * from widget
where name Like 'b[a-i]%'
Это будет соответствовать любой строке, где имя начинается с b, второй символ находится в диапазоне от a до i, а за ним следуют любые другие символы.
Я думаю, что я бы выбрал что-нибудь простое, например добавление строки высокой сортировки в конец верхней границы.Что-то вроде:
select * from widgetwhere name >= 'ba' and name <= 'bi'||'~'
Я не уверен, что это выдержит преобразование EBCDIC.
Вы также можете сделать это следующим образом:
select * from widget
where left(name, 2) between 'ba' and 'bi'
Если длина вашего критерия изменится (как вы, кажется, указали в оставленном вами комментарии), запрос также должен будет иметь длину в качестве входных данных:
declare @CriteriaLength int
set @CriteriaLength = 4
select * from widget
where left(name, @CriteriaLength) between 'baaa' and 'bike'