2016-11-22 1 views
1

Мне нужно разделить поле описания (свободный текст) на несколько строк. Формат в настоящее время по линии:(SQL) Определить позиции множественных вхождений строкового формата в поле

Case_Reference | Narrative 
```````````````|````````````````````````````````````` 
XXXX/XX-123456 | [Endless_Text up to ~50k characters] 

В области повествовательной как текст, отдельные записи (когда различные агенты сделали что-то к делу) начинается с даты ввода с последующими двумя пробелами (т.е. 'dd/mm/yyyy '), с значения дат изменяются с каждой записью в этом же поле.

Другими словами, после траления для лучшего разделителя, единственным, который я могу использовать, является этот формат строки, поэтому мне нужно идентифицировать несколько позиций в тексте Повествования, где формат (будет маскировать лучшее слово?) соответствует 'dd/mm/yyyy '.

можно определить несколько вхождений последовательной строки не проблема, но это его идентификации, где я в основном ищу:

'%[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9] %'

PATINDEX конечно возвращает первое вхождение/положение, но насколько я знаю, нет никакого способа «изменить» это (т. е. созданную функцию), чтобы позволить собирать остатки вхождений/позиций этого, как мы можем, с CHARINDEX (поскольку PATINDEX не имеет параметр начальной позиции).

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

Любая помощь будет очень оценена.

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

Желаемая выход будет

Case_Reference1 | 1st_Position_of_Delimiter_String 
Case_Reference1 | 2nd_Position_of_Delimiter_String 
Case_Reference2 | 1st_Position_of_Delimiter_String 
Case_Reference2 | 2nd_Position_of_Delimiter_String 
Case_Reference2 | 3rd_Position_of_Delimiter_String 
+1

Каков желаемый результат? Вы в настоящее время сказали нам маршрут, который хотите принять, но не готовый продукт. Там может быть лучший способ, чем маршрут, в котором вы сейчас работаете. – iamdave

+0

Лучший способ сделать это во время проглатывания данных с использованием языка программирования. Если вы хотите сделать то же самое для существующих данных, тогда вы можете получить только PATIndex. –

+0

Просьба указать некоторые строки строк – Shnugo

ответ

3

Вы могли бы решить эту проблему с помощью рекурсивных CTE

DECLARE @tbl TABLE (Case_Reference NVARCHAR(MAX),Narrative NVARCHAR(MAX)); 
INSERT INTO @tbl VALUES 
(N'C1',N'01/02/2000 Some text with  blanks 02/03/2000 More text 03/04/2000 An even more') 
,(N'C2',N'01/02/2000 Test for C2 02/03/2000 One more for C2 03/04/2000 An even more 04/05/2000 Blah') 
,(N'C3',N'01/02/2000 Test for C3 02/03/2000 One more for C3 03/04/2000 An even more') 
; 

WITH recCTE AS 
(
    SELECT 1 AS Step,Case_Reference,Narrative,CAST(1 AS BIGINT) AS StartsAt,NewPos.EndsAt+10 AS EndsAt,LEN(Narrative) AS MaxLen 
      ,SUBSTRING(Narrative,NewPos.EndsAt+10+1,999999) AS RestString 
    FROM @tbl AS tbl 
    CROSS APPLY(SELECT PATINDEX('%[0-3][0-9]/[0-1][0-9]/[1-2][0-9][0-9][0-9] %',SUBSTRING(Narrative,12,9999999))) AS NewPos(EndsAt) 

    UNION ALL 

    SELECT r.Step+1,r.Case_Reference,r.Narrative,r.EndsAt+1,CASE WHEN NewPos.EndsAt>0 THEN r.EndsAt+NewPos.EndsAt+10 ELSE r.MaxLen END,r.MaxLen 
      ,SUBSTRING(r.RestString,NewPos.EndsAt+10+1,999999) 
    FROM recCTE AS r 
    CROSS APPLY(SELECT PATINDEX('%[0-3][0-9]/[0-1][0-9]/[1-2][0-9][0-9][0-9] %',SUBSTRING(r.RestString,12,99999999))) AS NewPos(EndsAt) 
    WHERE r.EndsAt<r.MaxLen 
) 
SELECT Step,Case_Reference,StartsAt,EndsAt 
     ,SUBSTRING(Narrative,StartsAt,EndsAt-StartsAt+1) AS OutputString 
FROM recCTE 

ORDER BY Case_Reference,Step 

Результат

+------+----------------+----------+--------+---------------------------------------+ 
| Step | Case_Reference | StartsAt | EndsAt | OutputString       | 
+------+----------------+----------+--------+---------------------------------------+ 
| 1 | C1    | 1  | 38  | 01/02/2000 Some text with  blanks | 
+------+----------------+----------+--------+---------------------------------------+ 
| 2 | C1    | 39  | 60  | 02/03/2000 More text     | 
+------+----------------+----------+--------+---------------------------------------+ 
| 3 | C1    | 61  | 84  | 03/04/2000 An even more    | 
+------+----------------+----------+--------+---------------------------------------+ 
| 1 | C2    | 1  | 24  | 01/02/2000 Test for C2    | 
+------+----------------+----------+--------+---------------------------------------+ 
| 2 | C2    | 25  | 52  | 02/03/2000 One more for C2   | 
+------+----------------+----------+--------+---------------------------------------+ 
| 3 | C2    | 53  | 77  | 03/04/2000 An even more    | 
+------+----------------+----------+--------+---------------------------------------+ 
| 4 | C2    | 78  | 93  | 04/05/2000 Blah      | 
+------+----------------+----------+--------+---------------------------------------+ 
| 1 | C3    | 1  | 24  | 01/02/2000 Test for C3    | 
+------+----------------+----------+--------+---------------------------------------+ 
| 2 | C3    | 25  | 52  | 02/03/2000 One more for C3   | 
+------+----------------+----------+--------+---------------------------------------+ 
| 3 | C3    | 53  | 76  | 03/04/2000 An even more    | 
+------+----------------+----------+--------+---------------------------------------+ 
+0

Lorielus примечание Уточнение Шнуго рисунка также должно помочь избежать ложных совпадений –

+0

Большое спасибо Shnugo & James - если бы я мог отправить пиво через интернет, я бы! – Lorielus

1

Попробуйте рекурсивное CTE

declare @t table 
(
    caseref varchar(20), 
    narrative varchar(max) 
) 

insert into @t values('Case_Reference1', 'blah 10/11/2016 something 13/11/2016 something else'); 
insert into @t values('Case_Reference2', '11/11/2016 something 12/11/2016 something else 14/11/2016 something yet still'); 
insert into @t values('Case_Reference3', 'should find nothing'); 

with cte (caseref, pos, remainingstr) as 
(
    select caseref, 
     patindex('%[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9] %', narrative), 
     substring(narrative, patindex('%[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9] %', narrative) + 12, len(narrative) - 12 - patindex('%[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9] %', narrative)) 
    from @t 
    where patindex('%[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9] %', narrative) > 0 

    union all 

    select caseref, 
     pos + 12 + patindex('%[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9] %', remainingstr), 
     substring(remainingstr, patindex('%[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9] %', remainingstr) + 12, len(remainingstr) - 12 - patindex('%[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9] %', remainingstr)) 
    from cte 
    where patindex('%[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9] %', remainingstr) > 0 

) 
select caseref, pos 
from cte 
order by caseref, pos 
+1

Отлично, ты придерживался того же подхода, что и я, +1 с моей стороны.Один намек: я ценю возможность добавлять повторяющиеся выражения (например, 'patindex' в' CROSS APPLY (SELECT ...) 'и использовать их с именами говорящих. – Shnugo

Смежные вопросы