Если честно: это кошмар.T-SQL
- абсолютно неправильный инструмент для этого!
Только потому, что я поставил недостаточный (из-за вашего недостаточного вопроса) ответ, мне настоятельно рекомендуется как-то решить эту проблему.Это вопрос спортивного мастерства ...
DECLARE @mockup TABLE(ID INT IDENTITY, YourString VARCHAR(1000));
INSERT INTO @mockup VALUES
('AB 123456.123')
,('AB 123456/123')
,('AB 123456-123')
,('AB B0-23456.123')
,('AB 1234 5678 9545 3214.123')
,('AB 123456 123')
,('AB.123456 123')
,('AB..123456 123')
,('AB..1C23456 123')
,('AB 1234 5678 954 3214-12345.123');
- Кошмар
WITH CutForRules AS
(
SELECT t.ID
,t.YourString
,ROW_NUMBER() OVER(PARTITION BY t.ID ORDER BY (SELECT (NULL))) FragmentIndex
,c AsXml
,d.value('text()[1]','varchar(100)') Fragment
,ISNUMERIC(d.value('text()[1]','varchar(100)')) FragmentIsNum
,LEN(d.value('text()[1]','varchar(100)')) FragmentLength
,d.value('@dlmt','varchar(10)') Delimiter
FROM @mockup t
CROSS APPLY(SELECT REVERSE(SUBSTRING(t.YourString,PATINDEX('%[0-9]%',t.YourString),1000))) A(a)
CROSS APPLY(SELECT REVERSE(SUBSTRING(a,PATINDEX('%[ /.-]%',a)+1,1000))) B(b)
CROSS APPLY(SELECT CAST('<x>' + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(b,'/','|'),' ','</x><x dlmt=" ">'),'.','</x><x dlmt=".">'),'-','</x><x dlmt="-">'),'|','</x><x dlmt="/">') + '</x>' AS XML)) C(c)
CROSS APPLY c.nodes('/x') D(d)
)
SELECT t1.ID
,t1.YourString
,(
SELECT CONCAT(t2.Delimiter,t2.Fragment)
FROM CutForRules t2
WHERE t1.ID=t2.ID
AND (t2.FragmentIndex<(SELECT MIN(t3.FragmentIndex)
FROM CutForRules t3
WHERE t3.ID=t1.ID
AND t3.FragmentIndex>t2.FragmentIndex
AND t3.Delimiter=' '
AND t3.FragmentLength<4
AND t3.FragmentIsNum=1)
OR NOT EXISTS(SELECT 1 FROM CutForRules t4 WHERE t4.ID=t1.ID AND t4.Delimiter=' ' AND t4.FragmentLength<4)
)
ORDER BY t2.FragmentIndex
FOR XML PATH('')
)
FROM CutForRules t1
GROUP BY t1.ID,t1.YourString
ORDER BY t1.ID;
Вы можете поместить SELECT * FROM CutForRules
, чтобы увидеть промежуточный набор результатов, который я использую для этого.
Но я почти уверен, что вы придумаете О да, это работает, но есть еще один случай ...
Просто чтобы прояснить это:Я в этой точке; -)
ОБНОВЛЕНИЕ: Некоторые объяснения
Cte CutForRules вернет этот набор для моих тестовых данных:
+----+---------------------------------+---------+---+---+------+
| | YourString |Fragment | N | L | Delm |
+----+---------------------------------+---------+---+---+------+
| 1 | AB 123456.123 | 123456 | 1 | 6 | NULL |
+----+---------------------------------+---------+---+---+------+
| 2 | AB 123456/123 | 123456 | 1 | 6 | NULL |
+----+---------------------------------+---------+---+---+------+
| 3 | AB 123456-123 | 123456 | 1 | 6 | NULL |
+----+---------------------------------+---------+---+---+------+
| 4 | AB B0-23456.123 | 0 | 1 | 1 | NULL |
+----+---------------------------------+---------+---+---+------+
| 4 | AB B0-23456.123 | 23456 | 1 | 5 | - |
+----+---------------------------------+---------+---+---+------+
| 5 | AB 1234 5678 9545 3214.123 | 1234 | 1 | 4 | NULL |
+----+---------------------------------+---------+---+---+------+
| 5 | AB 1234 5678 9545 3214.123 | 5678 | 1 | 4 | |
+----+---------------------------------+---------+---+---+------+
| 5 | AB 1234 5678 9545 3214.123 | 9545 | 1 | 4 | |
+----+---------------------------------+---------+---+---+------+
| 5 | AB 1234 5678 9545 3214.123 | 3214 | 1 | 4 | |
+----+---------------------------------+---------+---+---+------+
| 6 | AB 123456 123 | 123456 | 1 | 6 | NULL |
+----+---------------------------------+---------+---+---+------+
| 7 | AB.123456 123 | 123456 | 1 | 6 | NULL |
+----+---------------------------------+---------+---+---+------+
| 8 | AB..123456 123 | 123456 | 1 | 6 | NULL |
+----+---------------------------------+---------+---+---+------+
| 9 | AB..1C23456 123 | 1C23456 | 0 | 7 | NULL |
+----+---------------------------------+---------+---+---+------+
| 10 | AB 1234 5678 954 3214-12345.123 | 1234 | 1 | 4 | NULL |
+----+---------------------------------+---------+---+---+------+
| 10 | AB 1234 5678 954 3214-12345.123 | 5678 | 1 | 4 | |
+----+---------------------------------+---------+---+---+------+
| 10 | AB 1234 5678 954 3214-12345.123 | 954 | 1 | 3 | |
+----+---------------------------------+---------+---+---+------+
| 10 | AB 1234 5678 954 3214-12345.123 | 3214 | 1 | 4 | |
+----+---------------------------------+---------+---+---+------+
| 10 | AB 1234 5678 954 3214-12345.123 | 12345 | 1 | 5 | - |
+----+---------------------------------+---------+---+---+------+
Предоставленное SELECT
сгруппирует это по ID,YourString
.Это означает: 1 строка на идентификатор.
Возвращенные столбцы - это столбцы группировки плюс большой вычисляемый.
Это коррелированный подзапрос .Он извлечет все строки для текущего идентификатора и обработает их.И его результат возвращается FOR XML PATH
, что является уловкой для объединения всех результатов.
Сложная часть в WHERE
: если после пробела с длиной есть хотя бы один числовой фрагмент1038 *, строка не будет включать этот и все последующие фрагменты.
Как получить элемент перед текущим элементом ?
Это снова коррелированный подзапрос , извлекающий элемент в ID-группе с FragmentIndex
большим, чем текущий.