Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
 Магический оператор LIKE.  [new]
_Промешан_
Member

Откуда:
Сообщений: 970
Друзья, подсобите. Кажется я зашел в тупой логический тупик.

У меня есть таблица RegExp, в которую я добавляю регулярные выражения. Ну такие, вида templ = [0-9]%D[abc]%
Много разных.
Потом по этой таблице я отбираю записи из др таблицы скажем Tools (все пока логично, да?), обновляю параметры и тд.
Условие на такую операцию - отсутствие пересекающихся регулярных выражений в одной группе для одного параметра (см ниже описание).
Ну то есть что подразумевается - что Tools.code LIKE '[0-9][0-9]%' и 'LIKE [0-9]%' гарантированно выдает разные результаты, но очевидно, что результат из первого LIKE входит в результат из второго LIKE.

Соотв нужна проверка пересечения при вставке нового выражения. Сначала я сделал просто тупо проверку по самой таблице RegExp через

select * from RegExp where templ like '%'+@new+'%' or @new like '%' + templ + '%'

проверил на нескольких вариантах и успокоился.
Ну а потом допетрил - что это не работает. Что посоветуете?

Описание таблицы
+
create table ##Tools (code varchar(200), group int, param2 int)/*, и тд*/
insert into ##Tools values('01456',1,0)  -- в обоих случаях попадает
insert into ##Tools values('11BD56',1,0)  -- в обоих случаях попадает
insert into ##Tools values('0G56',1,0)  -- этот не попадет для первого LIKE но попадет для второго
insert into ##Tools values('0G56',2,0)  -- этот не попадет для обоих, т.к. группа = 2 (см ниже)
create table ##RegExp (id int, templ varchar(200), group int, param int)
insert into ##RegExp (templ, group, param) values ('[0-9][0-9]%',1,1)
insert into ##RegExp (templ, group, param) values ('[0-9][0-9]%',1,2)

templ - регулярное выражение.
group - группа (одинаковое для обеих таблиц)
param - параметр.
По сути группа + параметр + темлп - это уникальный ключ.


Пример когда нельзя допустить вставку:
insert into ##RegExp (templ, group, param) values ('[0-9]%',1,1)

т.к. в группе 1 с выражением [0-9][0-9]% уже есть два параметра 1 и 2, а поскольку '[0-9]%' с группой 1 и параметром 1 - пересекаются, то нельзя допустить вставку (но только не методом уникального ключа, а методом проверок).

Зато можно вставить
insert into ##RegExp (templ, group, param) values ('[0-9]%',1,3)


Пожалуйста, напишите что думаете по этому поводу. Действительно ли нельзя обойтись простым LIKE и придется писать что то вроде?
+
declare @newtempl varchar(200) = '[0-9]%', @newgrp int=1, @newparam int = 1
select * from ##Tools t
  inner join ##RegExp re on t.code like re.templ and re.group = @newgrp and re.param = @newparam
where t.code like @newtempl

Иили другой вариант через INTERSECT - что будет означать что нашлось пересечение.


Нужно что то универсальное. т.к. есть еще задача, к примеру, переименования templ. Это означает, что допустим есть templ у которого уже несколько строк в таблице есть. И при переименовании надо проверять все эти строки (а не одну).
20 авг 12, 19:52    [13039253]     Ответить | Цитировать Сообщить модератору
 Re: Магический оператор LIKE.  [new]
Serg_77m
Member

Откуда: Донецк
Сообщений: 237
_Промешан_,

вообще-то, настоящие регулярные выражения имеют гораздо больше возможностей, чем шаблоны LIKE. Поэтому, предлагаю шаблоны LIKE называть шаблонами, чтобы не путаться в терминах.
По теме, это очень сложно. Не только одним LIKE не обойдётся, а и JOIN'а с LIKE окажется мало. Вот например, как отловить такое пересечение: '[0-9]%' и '[0-9A-Z]%'
А можно ведь и так записать: '[0123456789]%', и так: '[9870-6]%'
И ещё вопрос: что значит - пересечение шаблонов А и Б? Что любая строка, которая соответствует шаблону А, обязательно соответствует шаблону Б? Или что существует такая строка, которая соответствует одновременно шаблонам А и Б? Шаблоны '[0-7]%' и '[3-9]%' пересекаются или нет? Ведь строка '555' соответствует обоим.
А такие как проверять: '[0-9]%' и '_[0-9]%' ?

Я бы поискал другое решение.
20 авг 12, 20:23    [13039358]     Ответить | Цитировать Сообщить модератору
 Re: Магический оператор LIKE.  [new]
_Промешан_
Member

Откуда:
Сообщений: 970
Serg_77m
_Промешан_,

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

Я в курсе. С толку сбило выражение в справке regular characters.
По теме, это очень сложно. Не только одним LIKE не обойдётся, а и JOIN'а с LIKE окажется мало. Вот например, как отловить такое пересечение: '[0-9]%' и '[0-9A-Z]%'
А можно ведь и так записать: '[0123456789]%', и так: '[9870-6]%'
И ещё вопрос: что значит - пересечение шаблонов А и Б? Что любая строка, которая соответствует шаблону А, обязательно соответствует шаблону Б? Или что существует такая строка, которая соответствует одновременно шаблонам А и Б? Шаблоны '[0-7]%' и '[3-9]%' пересекаются или нет? Ведь строка '555' соответствует обоим.
А такие как проверять: '[0-9]%' и '_[0-9]%' ?

Я бы поискал другое решение.

Вы бы поискали другое решение в сравнении с каким решением?
20 авг 12, 20:43    [13039440]     Ответить | Цитировать Сообщить модератору
 Re: Магический оператор LIKE.  [new]
Serg_77m
Member

Откуда: Донецк
Сообщений: 237
_Промешан_
Вы бы поискали другое решение в сравнении с каким решением?
В смысле, не стал бы заниматься анализом шаблонов с целью выловить пересечения. Если задача состоит только в том, чтобы некая таблица со строками (Tools?) при связке с RegExp при помощи LIKE не выдала двойников, то при связывании я бы вместо INNER JOIN ставил CROSS APPLY + TOP 1. А в таблицу RegExp добавил бы поле "ранг" или "приоритет", чтобы однозначно выбирать один из шаблонов, в случае когда их соответствует несколько. Примерно так:
select *
from ##Tools a
  cross apply (
    select top 1 *
    from #RegExp b
    where b.group=a.group and a.code like b.templ
    order by b.rang
  ) b
20 авг 12, 20:56    [13039487]     Ответить | Цитировать Сообщить модератору
 Re: Магический оператор LIKE.  [new]
_Промешан_
Member

Откуда:
Сообщений: 970
Serg_77m
_Промешан_
Вы бы поискали другое решение в сравнении с каким решением?
В смысле, не стал бы заниматься анализом шаблонов с целью выловить пересечения. Если задача состоит только в том, чтобы некая таблица со строками (Tools?) при связке с RegExp при помощи LIKE не выдала двойников, то при связывании я бы вместо INNER JOIN ставил CROSS APPLY + TOP 1. А в таблицу RegExp добавил бы поле "ранг" или "приоритет", чтобы однозначно выбирать один из шаблонов, в случае когда их соответствует несколько. Примерно так:
select *
from ##Tools a
  cross apply (
    select top 1 *
    from #RegExp b
    where b.group=a.group and a.code like b.templ
    order by b.rang
  ) b
Интересно, посмотрим.
Но вот другая сложность возникла.
На момент добавления шаблона, пересечений (если смотреть по Tools) может и не быть. Но они могут появиться в следствие добавления соотв записей в Tools, которые отвечаю одному и более шаблону.

Вот тут я и задумался... То есть даже по Tools будет не верным искать пересечения. и что делать, господа?

пс: разумеется таблица Tools более приоритена чем RegExp, то есть в Tools обязательно заносятся все записи.
21 авг 12, 15:08    [13043732]     Ответить | Цитировать Сообщить модератору
 Re: Магический оператор LIKE.  [new]
Mnior
Member

Откуда: Кишинёв
Сообщений: 6723
Да чё тут думать. В лоб как есть.
Триггер (пост проверка) на обе таблы и проверять новые/изменённые/удалённые записи (INSERTED/DELETED) с соответствующей логикой.
При вставке в RegExp проверяется INSERTED JOIN Tools (DELETED аналогично), а для Tools соответственно INSERTED JOIN RegExp.
Если надо чтобы дублей небыло, то решайте административный процесс: или запрещать дубли или оповещать для уточнения RegExp.
Надёюсь вы поняли и запросы сами знаете как написать.
21 авг 12, 21:31    [13045804]     Ответить | Цитировать Сообщить модератору
 Re: Магический оператор LIKE.  [new]
_Промешан_
Member

Откуда:
Сообщений: 970
Mnior
Да чё тут думать. В лоб как есть.
Триггер (пост проверка) на обе таблы и проверять новые/изменённые/удалённые записи (INSERTED/DELETED) с соответствующей логикой.
При вставке в RegExp проверяется INSERTED JOIN Tools (DELETED аналогично), а для Tools соответственно INSERTED JOIN RegExp.
Если надо чтобы дублей небыло, то решайте административный процесс: или запрещать дубли или оповещать для уточнения RegExp.
Надёюсь вы поняли и запросы сами знаете как написать.

Без триггеров (политика такая). И ваше предложение мимо, т.к. я уже писал выше.

Сравнение нужно проводить как-то между самими масками, а не по Tools.
22 авг 12, 13:26    [13048859]     Ответить | Цитировать Сообщить модератору
 Re: Магический оператор LIKE.  [new]
Serg_77m
Member

Откуда: Донецк
Сообщений: 237
_Промешан_,

смысл задачи какой? Нужно чтобы в принципе нельзя было ввести две маски, которые обе могут сопоставиться с некоторой строкой? Действительно так надо?
22 авг 12, 14:00    [13049156]     Ответить | Цитировать Сообщить модератору
 Re: Магический оператор LIKE.  [new]
_Промешан_
Member

Откуда:
Сообщений: 970
Serg_77m
_Промешан_,

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

Таблица RegExp содержит маски, по которым производится простановка значений в таблице Tools.
Соответственно code и group - это уникальное сочетание для таблицы Tools.
Если в RegExp попадается две маски, которые проставляют одни и те же параметры разными значениями (ну например значение для Tools.param1 имеется как у маски [0-9]% так и у маски [0-9][0-9]% для group = 5), то это не правильно. таких записей не должно появиться. То есть во-первых, при появлении таких пересечений, мы проходим два и более раз одни и те же записи Tools, и во-вторых, проставляем значения для этих Tools с большой вероятностью не правильные.

Так что все как вы спрашиваете - действительно надо, что бы нельзя было ввести две маски, которые обе могут сопоставиться с некоторой строкой.

Для справки: всего таких шаблонов - около 5-6 тысяч на 100-150 групп. То есть в каждой группе может быть от 1 до 70 примерно шаблонов. (пересечения нельзя допускать в рамках одной группы и одних и тех же параметрах).
Записей в Tools порядка 10 млн. Много в общем. Нагрузка на Tools постоянно, поэтому никакой такой проверки, тем более триггеров, делать мы не будем - это убьет сервер нахрен (особенно если придется проверять все маски между собой в одной группе - это для того, если внесли руками в базу, а не черзе интерфейс.)
22 авг 12, 14:49    [13049597]     Ответить | Цитировать Сообщить модератору
 Re: Магический оператор LIKE.  [new]
_Промешан_
Member

Откуда:
Сообщений: 970
_Промешан_
Serg_77m
_Промешан_,

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

Таблица RegExp содержит маски, по которым производится простановка значений в таблице Tools.
Соответственно code и group - это уникальное сочетание для таблицы Tools.
Если в RegExp попадается две маски, которые проставляют одни и те же параметры разными значениями (ну например значение для Tools.param1 имеется как у маски [0-9]% так и у маски [0-9][0-9]% для group = 5), то это не правильно. таких записей не должно появиться. То есть во-первых, при появлении таких пересечений, мы проходим два и более раз одни и те же записи Tools, и во-вторых, проставляем значения для этих Tools с большой вероятностью не правильные.

Так что все как вы спрашиваете - действительно надо, что бы нельзя было ввести две маски, которые обе могут сопоставиться с некоторой строкой.

Для справки: всего таких шаблонов - около 5-6 тысяч на 100-150 групп. То есть в каждой группе может быть от 1 до 70 примерно шаблонов. (пересечения нельзя допускать в рамках одной группы и одних и тех же параметрах).
Записей в Tools порядка 10 млн. Много в общем. Нагрузка на Tools постоянно, поэтому никакой такой проверки, тем более триггеров, делать мы не будем - это убьет сервер нахрен (особенно если придется проверять все маски между собой в одной группе - это для того, если внесли руками в базу, а не черзе интерфейс.)

То есть нужно как-то постараться сравнить маски между собой. Вот и как это можно сделать?
22 авг 12, 14:50    [13049613]     Ответить | Цитировать Сообщить модератору
 Re: Магический оператор LIKE.  [new]
invm
Member

Откуда: Москва
Сообщений: 9723
_Промешан_
То есть нужно как-то постараться сравнить маски между собой. Вот и как это можно сделать?
Дерзайте.

ЗЫ: Интересно, по скольким граблям вам нужно прогуляться, чтобы заняться уже рефакторингом БД, а не строительством костылей?
22 авг 12, 15:29    [13050002]     Ответить | Цитировать Сообщить модератору
 Re: Магический оператор LIKE.  [new]
_Промешан_
Member

Откуда:
Сообщений: 970
invm
_Промешан_
То есть нужно как-то постараться сравнить маски между собой. Вот и как это можно сделать?
Дерзайте.

ЗЫ: Интересно, по скольким граблям вам нужно прогуляться, чтобы заняться уже рефакторингом БД, а не строительством костылей?
Ну заниматься не мне, тк придумывал не я.
У вас есть идеи как можно решить данную задачу рефакторингом?
22 авг 12, 18:29    [13051348]     Ответить | Цитировать Сообщить модератору
 Re: Магический оператор LIKE.  [new]
invm
Member

Откуда: Москва
Сообщений: 9723
_Промешан_
У вас есть идеи как можно решить данную задачу рефакторингом?
Какую задачу? Найти пересечение двух шаблонов средствами T-SQL? Никак. Потому что нельзя подвергнуть рефакторингу то, чего еще нет.
Другие предложенные способы решения, не связанные с анализом шаблонов, вас не устроили. Так что -- тупик.
22 авг 12, 20:19    [13051729]     Ответить | Цитировать Сообщить модератору
 Re: Магический оператор LIKE.  [new]
_Промешан_
Member

Откуда:
Сообщений: 970
invm
_Промешан_
У вас есть идеи как можно решить данную задачу рефакторингом?
Какую задачу? Найти пересечение двух шаблонов средствами T-SQL? Никак. Потому что нельзя подвергнуть рефакторингу то, чего еще нет.
Другие предложенные способы решения, не связанные с анализом шаблонов, вас не устроили. Так что -- тупик.


Но мне интересно, как все-таки можно решить рефакторингом добавление шаблонов для проставления параметров, при этом избежать пересечение.
22 авг 12, 21:06    [13051901]     Ответить | Цитировать Сообщить модератору
 Re: Магический оператор LIKE.  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31865
_Промешан_
invm
пропущено...
Какую задачу? Найти пересечение двух шаблонов средствами T-SQL? Никак. Потому что нельзя подвергнуть рефакторингу то, чего еще нет.
Другие предложенные способы решения, не связанные с анализом шаблонов, вас не устроили. Так что -- тупик.


Но мне интересно, как все-таки можно решить рефакторингом добавление шаблонов для проставления параметров, при этом избежать пересечение.
Очевидно же, что нельзя решить такую задачу.

Максимум - можно проверять отсутствие пересечений на существующих данных.
22 авг 12, 22:22    [13052142]     Ответить | Цитировать Сообщить модератору
 Re: Магический оператор LIKE.  [new]
Serg_77m
Member

Откуда: Донецк
Сообщений: 237
Я догадываюсь где такое может быть нужно. Скажем, таблица Tools - это база действующих телефонных номеров мобильного оператора, а в таблице RegExp лежит стоимость звонков и SMS для каждой группы номеров. Номера постоянно добавляются и удаляются, а тариф определяется номером по шаблону. Ну примерно так: на номера вида '101%' тариф один, на '102%' - другой, а на '[2-9]%' - третий. Соответственно, надо при регистрации нового номера сразу автоматически присвоить ему тариф. И совершенно недопустимо, чтобы одному вновь добавленному номеру соответствовало два тарифа.

Мне кажется, это решаемо. Шаблоны LIKE намного проще регулярных выражений. Есть одно соображение. Если все шаблоны содержат символ процента, то всё упрощается. Достаточно выделить из шаблона префикс (от начала строки до первого процента) и суффикс (от последнего процента до конца строки). Затем последовательно сопоставить префиксы и суффиксы двух тестируемых шаблонов, если они оба дают конфликт, то и весь шаблон даёт конфликт, а если конфликта нет, то и полный шаблон конфликта не даёт. Ну да, придётся разбить шаблон на атомы (так, чтобы конструкцию вида '[0-9]' считать отдельным атомом), завести таблицу-алфавит, в которой будут перечислены все символы, которые могут встретиться в Tools (а в Tools прописать соответствующее ограничение CHECK), затем для каждой пары атомов из двух шаблонов найти символ из таблицы-алфавита, который сопоставится одновременно с обоими. Поскольку процентов в префиксе и суффиксе нет, то каждый символ можно подбирать независимо от других. Триггер придётся ставить на RegExp, который будет проверять добавляемые и изменяемые шаблоны на конфликты с уже существующими, но ведь на неё нагрузка по записи небольшая, сервер ведь не ляжет? Всё равно без него никак.

Но сначала определиться с алгоритмом. А потом уже оптимизировать. Бывают ли шаблоны без '%'? Если бывают, то задача усложняется.
22 авг 12, 22:23    [13052149]     Ответить | Цитировать Сообщить модератору
 Re: Магический оператор LIKE.  [new]
Serg_77m
Member

Откуда: Донецк
Сообщений: 237
_Промешан_,

я ещё подумаю, если будут идеи - напишу.
22 авг 12, 22:28    [13052164]     Ответить | Цитировать Сообщить модератору
 Re: Магический оператор LIKE.  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31865
Serg_77m
Я догадываюсь где такое может быть нужно. Скажем, таблица Tools - это база действующих телефонных номеров мобильного оператора, а в таблице RegExp лежит стоимость звонков и SMS для каждой группы номеров. Номера постоянно добавляются и удаляются, а тариф определяется номером по шаблону. Ну примерно так: на номера вида '101%' тариф один, на '102%' - другой, а на '[2-9]%' - третий. Соответственно, надо при регистрации нового номера сразу автоматически присвоить ему тариф. И совершенно недопустимо, чтобы одному вновь добавленному номеру соответствовало два тарифа.
Такая задача решается диапазонами или просто списками, какие тут шаблоны?
Serg_77m
Мне кажется, это решаемо. Шаблоны LIKE намного проще регулярных выражений. Есть одно соображение. Если все шаблоны содержат символ процента, то всё упрощается.
По моему, вы рассматриваете сильно упрощённую версию. Хотя шаблоны и просты, но не настолько же :-)

Допустим, как определить, что пересекаются:
'[1-23-79]' и '[54]'
и не пересекаются
'[1-26-79]' и '[54]'
22 авг 12, 22:47    [13052224]     Ответить | Цитировать Сообщить модератору
 Re: Магический оператор LIKE.  [new]
Mnior
Member

Откуда: Кишинёв
Сообщений: 6723
invm
Дерзайте.
Уже пытался изначально, хоть и поверхностно, - не радужно. Часто в научные статьи заносит.
Очень похоже на проблему похожести слов (только сложнее), которая не столь быстрая.
Т.е. лучше обрабатывать не на скуле, хотя бы в CLR-е.

Serg_77m
Я догадываюсь где такое может быть нужно. Скажем, таблица Tools - это база действующих телефонных номеров мобильного оператора, а в таблице RegExp лежит стоимость звонков и SMS для каждой группы номеров.
Всё становится проще на частностях, таже теорема ферма.
Для телефонных никакие % не нужны, там маски бетонные.
Serg_77m, это слишком титаническая работа, лучше уж ТС немного уточнит задачу, может там можно очень простые маски использовать.
Например, я иногда свой "язык" для LIKE придумываю: Несколько спецсимволов, которые потом в LIKE форму перевожу. Естественно на таких ограничениях (микро-словаре) все комбинации можно обработать.

Но всё равно не решается проблема изменения RegExp. Всё равно надо имеющие лимоны Tools проверять, как ни крути и не отбрыкивайся - это неизбежно.

В сторону пере-проектирования, кину просто песчинку, чисто для затравки. Может сначала стоит разбить пространство Code на многие маленькие логические зоны, (ну типа как на параллели и меридианы), а далее уже рулить этими зонами - покрывающие области. Т.е. при изменении области находим зоны "выпавшие из" / "попавшие в" и по индексу быстро разруливаем. Может аналогия со spatial index вас наведёт на что-то.
22 авг 12, 23:07    [13052308]     Ответить | Цитировать Сообщить модератору
 Re: Магический оператор LIKE.  [new]
Serg_77m
Member

Откуда: Донецк
Сообщений: 237
_Промешан_,

ещё вопрос: версия SQL какая?
22 авг 12, 23:27    [13052377]     Ответить | Цитировать Сообщить модератору
 Re: Магический оператор LIKE.  [new]
Mnior
Member

Откуда: Кишинёв
Сообщений: 6723
alexeyvg
Допустим, как определить, что пересекаются:
'[1-23-79]' и '[54]'
и не пересекаются
'[1-26-79]' и '[54]'
А чё сложного? Строить диапазоны: 3 < 5 < 7
[a-b] и [A-B] => a < B & A < b, для каждого под-диапазона.
Или вы на скуле хотите всё это добро парсить? Хотя можно.
Перестановки сложнее IMXO.
%_[][^]
%????
_?+++
[]?+**
[^]?+**
% разбивать надо на варианты: съесть / не съесть.
[^] - запретить. Или обратный вид диапазона.

Ну допустим напишем. А что дальше? Пересечение запретим, а если шаблон надо изменить?
23 авг 12, 00:41    [13052637]     Ответить | Цитировать Сообщить модератору
 Re: Магический оператор LIKE.  [new]
invm
Member

Откуда: Москва
Сообщений: 9723
Mnior
Т.е. лучше обрабатывать не на скуле, хотя бы в CLR-е.
Именно так.
23 авг 12, 00:46    [13052644]     Ответить | Цитировать Сообщить модератору
 Re: Магический оператор LIKE.  [new]
_Промешан_
Member

Откуда:
Сообщений: 970
Во-первых всем спасибо за ответы и желание (или хотя бы интересно) что-то с этим делать.

Уточняю задачу: Она сводится к парсингу кодов товаров, которые разумеется могут быть любыми от разных поставщиков. В этом коде сокрыты разные параметры, которые уже более менее известны. (разный поставщик кодирует по-своему).


Ограничение применимости масок есть по поставщику. то есть две одинаковые (или пересекающиеся по результату LIKE) маски у двух поставщиков могут быть.А вот у одного поставщика - не должно быть, если эти маски "описывают" один и тот же параметр. Ну например маска ABC%0 и AB[D-H]% не должны быть в БД с одним и тем же параметром Длинна.

Эти шаблоны самые разнообразные. С применением всевозможных вариаций, на которые способен разум поставшика.

Надеюсь это немного прояснит ситуацию.

Самое понятное (но не идеальное) решение - это сравнение по тем данным что уже есть и в дальнейшем проверка при добавлении (что не айс, т.к. добавляется/обновляется скажем мульен товаров в автоматическом режиме (из прайса)) либо по джобу или при повторном просмотре шаблонов в интерфейсе.

но это не идеал. увы.
23 авг 12, 19:36    [13057243]     Ответить | Цитировать Сообщить модератору
 Re: Магический оператор LIKE.  [new]
_Промешан_
Member

Откуда:
Сообщений: 970
Microsoft SQL Server 2008 (SP3) - 10.0.5500.0 (X64)   Sep 21 2011 22:45:45   
Copyright (c) 1988-2008 Microsoft Corporation  Standard Edition (64-bit) on Windows NT 6.0 <X64> (Build 6002: Service Pack 2)
23 авг 12, 19:37    [13057246]     Ответить | Цитировать Сообщить модератору
 Re: Магический оператор LIKE.  [new]
Serg_77m
Member

Откуда: Донецк
Сообщений: 237
_Промешан_,

вроде получилось. Сопоставление "в лоб". Будет плохо работать, если шаблоны содержат много процентов. Но это можно оптимизировать, если народ подскажет, как проще всего проверить: есть ли в строке символ процента, который НЕ находится внутри квадратных скобки. У меня сходу написать такую проверку не получается.

Тестовый пример проверяет пересечение всех шаблонов в t_regex между собой. Если вставить в триггер, то вместо одной из t_regex подставить inserted. Может быть, придётся добавить option (maxrecursion NNN).
Если выборка непуста - пересечение есть.

+
if object_id('t_regex') is not null drop table t_regex
if object_id('t_alpha') is not null drop table t_alpha
if object_id('f_find_conflicting_symbol') is not null drop function f_find_conflicting_symbol
if object_id('f_find_conflict') is not null drop function f_find_conflict
go

create table t_regex (pattern varchar(100) not null,grp int not null,id int identity)
create table t_alpha (symbol char(1) primary key)
go

-- Таблица-алфавит. В неё надо вписать все символы, которые могут встречаться в строках.
insert into t_alpha (symbol) values ('0')
insert into t_alpha (symbol) values ('1')
insert into t_alpha (symbol) values ('2')
insert into t_alpha (symbol) values ('3')
insert into t_alpha (symbol) values ('4')
insert into t_alpha (symbol) values ('5')
insert into t_alpha (symbol) values ('6')
insert into t_alpha (symbol) values ('7')
insert into t_alpha (symbol) values ('8')
insert into t_alpha (symbol) values ('9')
go

create function f_find_conflicting_symbol(@pat1 varchar(1000),@pat2 varchar(1000))
returns table as return
select top 1 symbol,
  substring(@pat1, case left(@pat1,1) 
                     when '[' then nullif(charindex(']',@pat1),0)+1 
                     else 2 
                   end,1000) as pat1,
  substring(@pat2, case left(@pat2,1)
                     when '[' then nullif(charindex(']',@pat2),0)+1 
                     else 2
                   end,1000) as pat2
from t_alpha
where symbol like substring(@pat1,1,case when left(@pat1,1)='[' then nullif(charindex(']',@pat1),0) else 1 end)
  and symbol like substring(@pat2,1,case when left(@pat2,1)='[' then nullif(charindex(']',@pat2),0) else 1 end)
go

-- Поиск конфликта между двумя шаблонами
create function f_find_conflict(@pattern1 varchar(1000),@pattern2 varchar(1000))
returns table as return
with cfl (pat1,pat2,string) as (
  select @pattern1,@pattern2,cast('' as varchar(1000))
  union all
  select 
    case when left(a.pat1,1)='%' then a.pat1 else b.pat1 end,
    case when left(a.pat2,1)='%' then a.pat2 else b.pat2 end,
    cast(a.string+b.symbol as varchar(1000))
  from cfl a
    cross apply f_find_conflicting_symbol(a.pat1,a.pat2) b
  where left(a.pat1,1)<>'%' or left(a.pat2,1)<>'%'
  union all
  select substring(a.pat1,2,1000),a.pat2,a.string
  from cfl a
  where left(a.pat1,1)='%'
  union all
  select a.pat1,substring(a.pat2,2,1000),a.string
  from cfl a
  where left(a.pat2,1)='%'
)
select top 1 string  -- строка, вызывающая конфликт
from cfl
where pat1='' and pat2=''
go

-- Таблица шаблонов
insert into t_regex (pattern,grp) values ('5[0-9]%',1)
insert into t_regex (pattern,grp) values ('4[^89]%1',1)
insert into t_regex (pattern,grp) values ('3[23]%1%1',1)
insert into t_regex (pattern,grp) values ('3[456]%1%1',1)
insert into t_regex (pattern,grp) values ('3[3]%1%2',1)
insert into t_regex (pattern,grp) values ('3133121',1)
insert into t_regex (pattern,grp) values ('4[0-6]%1%2',1)
insert into t_regex (pattern,grp) values ('12%23',1)
insert into t_regex (pattern,grp) values ('789',1)
--insert into t_regex (pattern,grp) values ('4[5-9]6%',1)
go

-- Тестовый пример
select *
from t_regex a
  inner join t_regex b on b.grp=a.grp and a.id<>b.id
  cross apply f_find_conflict(a.pattern,b.pattern) c
23 авг 12, 20:54    [13057487]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
Все форумы / Microsoft SQL Server Ответить