Как проверить строку есть пользовательский шаблон в SQL Server - PullRequest
0 голосов
/ 28 апреля 2019

У меня есть такой столбец:

Codes
--------------------------------------------------
3/1151---------366-500-2570533-1
9/6809---------------------368-510-1872009-1  
1-260752-305-154----------------154-200-260752-1--------154-800-13557-1
2397/35425---------------------------------377-500-3224575-1
17059----------------377-500-3263429-1
126/42906---------------------377-500-3264375-1
2269/2340-------------------------377-500-3065828-1
2267/767---------377-500-1452908-4
2395/118593---------377-500-3284699-1
2395/136547---------377-500-3303413-1
92/10260---------------------------377-500-1636038-1
2345-2064---------377-500-3318493-1
365-2290--------377-500-3278261-12
365-7212--------377-500-2587120-1

Как мне извлечь коды в этом формате:

3digit-3digit-5to7digit-1to2digit
xxx-xxx-xxxxxx-xx

Результат должен быть:

Codes
--------------------------------------------------
366-500-2570533-1
368-510-1872009-1  
154-200-260752-1 , 154-800-13557-1     -- have 2 code template
377-500-3224575-1
377-500-3263429-1
377-500-3264375-1
377-500-3065828-1
377-500-1452908-4
377-500-3284699-1
377-500-3303413-1
377-500-1636038-1
377-500-3318493-1
377-500-3278261-12
377-500-2587120-1
------------------------------------

Эта проблема полностью устала от меня.

Спасибо, что прочитали о моей проблеме

Ответы [ 2 ]

1 голос
/ 28 апреля 2019

Это действительно ужасно, действительно ужасно.Я ни на секунду не предлагаю делать это в вашей РСУБД, и на самом деле я предлагаю вам исправить ваши данные.Вам не следует хранить данные с разделителями (я использую это слово для описания ваших данных) в таблицах, в которых вы должны хранить отдельные столбцы и строки.В этом случае первый «код» должен быть в одном столбце с отношением один ко многим с другой таблицей с кодами, которые вы пытаетесь извлечь.

Поскольку вы не пометили или не упомянули свою версиюSQL Server я использовал последний синтаксис SQL Server.STRING_SPLIT доступно в SQL Server 2016+ и STRING_AGG в 2017+.Если вы не используете эти версии, вам нужно заменить эти функции подходящей альтернативой (я предлагаю delimitedsplit8k(_lead) и FOR XML PATH соответственно).


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

Поскольку ваш разделитель непоследователен (он не имеет одинаковой ширины), в результате некоторые коды будут иметь начальный дефис, поэтому мне нужноизбавиться от этого.Затем я использую мой ответ на ваш другой вопрос , чтобы разбить код дальше на его компоненты и обратить обратно WHERE;Раньше ответ искал «плохие» строки, где, как и сейчас, мы хотим «хорошие» строки.

Затем, после всего этого, это так же «просто», как использование STRING_AGG для разграничения «хороших» строк.:

SELECT STRING_AGG(ca.Code,',') AS Codes
FROM (VALUES('3/1151---------366-500-2570533-1'),
            ('9/6809---------------------368-510-1872009-1'),
            ('1-260752-305-154----------------154-200-260752-1--------154-800-13557-1'),
            ('2397/35425---------------------------------377-500-3224575-1'),
            ('17059----------------377-500-3263429-1'),
            ('126/42906---------------------377-500-3264375-1'),
            ('2269/2340-------------------------377-500-3065828-1'),
            ('2267/767---------377-500-1452908-4'),
            ('2395/118593---------377-500-3284699-1'),
            ('2395/136547---------377-500-3303413-1'),
            ('92/10260---------------------------377-500-1636038-1'),
            ('2345-2064---------377-500-3318493-1'),
            ('365-2290--------377-500-3278261-12'),
            ('365-7212--------377-500-2587120-1')) V(Codes)
    CROSS APPLY (VALUES(REPLACE(V.Codes,'--','|'))) D(DelimitedCodes)
    CROSS APPLY STRING_SPLIT(D.DelimitedCodes,'|') SS
    CROSS APPLY (VALUES(CASE LEFT(SS.[value],1) WHEN '-' THEN STUFF(SS.[value],1,1,'') ELSE SS.[value] END)) ca(Code)
    CROSS APPLY (VALUES(PARSENAME(REPLACE(ca.Code,'-','.'),4),
                        PARSENAME(REPLACE(ca.Code,'-','.'),3),
                        PARSENAME(REPLACE(ca.Code,'-','.'),2),
                        PARSENAME(REPLACE(ca.Code,'-','.'),1))) PN(P1, P2, P3, P4)
WHERE LEN(PN.P1) = 3
   AND LEN(PN.P2) = 3
   AND LEN(PN.P3) BETWEEN 5 AND 7
   AND LEN(PN.P4) BETWEEN 1 AND 2
   AND ca.Code NOT LIKE '%[^0-9\-]%' ESCAPE '\'
GROUP BY V.Codes;

дБ <> скрипка

0 голосов
/ 28 апреля 2019

У вас есть несколько проблем здесь:

  • Разделение ваших более длинных строк на нужные вам коды.
  • Работа с тем фактом, что ваш разделитель для более длинных строк такой же, как вашразделитель для более коротких.
  • Поиск шаблонов, которые вы хотите.

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

Вот решение, которое извлекает нужные значения:

with t as (
      select v.*
      from (values ('3/1151---------366-500-2570533-1'), 
                   ('9/6809---------------------368-510-1872009-1'), 
                   ('1-260752-305-154----------------154-200-260752-1--------154-800-13557-1'),
                   ('2397/35425---------------------------------377-500-3224575-1')
           ) v(str)
     )
select t.*, ss.value
from t cross apply
     (values (replace(replace(replace(replace(replace(t.str, '--', '><'), '<>', ''), '><', '|'), '|-', '|'), '-|', '|'))
     ) v(str_sep) cross apply
     string_split(v.str_sep, '|') ss
where ss.value like '%-%-%-%' and
      ss.value not like '%-%-%-%-%' and
      (ss.value like '[0-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9]-[0-9]' or
       ss.value like '[0-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9]-[0-9][0-9]' or
       ss.value like '[0-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9]-[0-9]' or
       ss.value like '[0-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9]' or
       ss.value like '[0-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9]' or
       ss.value like '[0-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9]'
      );

Здесь - это дБ <> скрипка.

Я бы настоятельно рекомендовал вам найти какой-нибудь способвыполнения этой строки в любом месте, отличном от SQL.

Ключом к этой работе является получение длинной строки дефисов до одного разделителя.SQL Server не предлагает регулярные выражения для дефисов (как это делают некоторые другие базы данных и как доступно на других языках программирования).Например, в Python это было бы намного проще.

Странный оператор values с заменой zillion обрабатывает повторяющиеся разделители, заменяя их одним разделителем канала.

Примечание:Это использует string_split() для удобства.Он был представлен в SQL Server 2017. Для более ранних версий в Интернете имеется множество примеров функций разделения строк.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...