Без какой-либо функции или внешнего RegEx вы можете пройти этот маршрут:
;WITH cte AS
(
SELECT *
,CAST(CONCAT('<x><y>',REPLACE(REPLACE(LogValue,' to ','</y><y>'),' ','</y></x><x><y>'),'</y></x>') AS XML) AS CastedToXml
FROM #temp
)
SELECT cte.*
,numberY.value('/y[1]','int') AS SourceID
,numberY.value('/y[2]','int') AS DestinationID
FROM cte
CROSS APPLY (SELECT CastedToXml.query('/x[not(empty(y[1] cast as xs:int?))
and not(empty(y[2] cast as xs:int?))]/y')) A(numberY);
Идея вкратце:
- Мы используем некоторые замены для преобразования вашей строки в XML (особенно
' to '
)
Нажмите одну из XML -гиперссылок, чтобы увидеть промежуточную XML.
<x>
<y>Status</y>
</x>
<x>
<y>changed</y>
</x>
<x>
<y>from</y>
</x>
<x>
<y>1</y>
<y>10</y>
</x>
- Будет
APPLY
используйте .query()
для выбора каждого <x>
, где мы находим два <y>
с возможностью преобразования в int. - Теперь мы можем выбрать первое и второе, чтобы вернуть ваши значения.
ОБНОВЛЕНИЕ
Использование этого в cte добавило бы атрибут маркировки, когда from
или to
было до числа:
,CAST(CONCAT('<x><y>',REPLACE(REPLACE(REPLACE(REPLACE(LogValue,' from ',' to '),' to ','</y><y*>'),' ','</y></x><x><y>'),'<y*>','<y takeThis="true">'),'</y></x>') AS XML) AS CastedToXml
Промежуточный XML был бы тогда выглядит так
( внимание: Я изменил входные данные с шум , например from Vienna to London
или числа в других местах):
<x>
<y>Mary</y>
<y takeThis="true">vienna</y>
<y takeThis="true">london</y>
</x>
<x>
<y>had</y>
<y takeThis="true">3</y>
</x>
<!-- shortened for brevity -->
<x>
<y>changed</y>
<y takeThis="true">4</y>
<y takeThis="true">12</y>
</x>
Это позволяет избежать ложных срабатываний (например, два числа в адресе)
Довольно толерантный запрос lly:
;WITH cte AS
(
SELECT *
,CAST(CONCAT('<x><y>',REPLACE(REPLACE(REPLACE(REPLACE(LogValue,' from ',' to '),' to ','</y><y*>'),' ','</y></x><x><y>'),'<y*>','<y takeThis="true">'),'</y></x>') AS XML) AS CastedToXml
FROM #temp
)
SELECT cte.*
,numberY.value('/y[1]','int') AS SourceID
,numberY.value('/y[2]','int') AS DestinationID
FROM cte
CROSS APPLY (SELECT CastedToXml.query('for $x in /x[count(y[@takeThis="true"])=2]
for $y in $x/y
return if(not(empty($y cast as xs:int?))) then $y else null')) A(numberY);
Он использует XQuery-FLWOR, чтобы уменьшить набор до нужных вам фигур. Это поможет справиться с нарушением других чисел в вашей строке.
Фильтр будет искать элементы <x>
, где есть два элемента <y>
с атрибутом takeThis="true
, и будет возвращать эти <y>
элементы, только если преобразуются в int.