Вот рекурсивная версия CTE, которая, будем надеяться, будет немного быстрее, чем итеративная UDF:
DECLARE @Data nvarchar(1000)
SET @Data = N'...{cloak:id=1.1.1}...{cloak}...{cloak:id=1.1.2}...{cloak}...' +
N'{cloak:id=1.1.3}...{cloak}...'
;WITH Cloak_CTE AS
(
SELECT
CAST(NULL AS nvarchar(50)) AS requirement_num,
CHARINDEX('{cloak:id=', @Data) AS start_index,
CHARINDEX('}', @Data, CHARINDEX('{cloak:id=', @Data)) AS end_index
UNION ALL
SELECT
CAST(SUBSTRING(@Data, start_index + 10,
end_index - start_index - 10) AS nvarchar(50)),
CHARINDEX('{cloak:id=', @Data, end_index + 1),
CHARINDEX('}', @Data, CHARINDEX('{cloak:id=', @Data, end_index + 1))
FROM Cloak_CTE
WHERE start_index > 0
)
SELECT requirement_num
FROM Cloak_CTE
WHERE requirement_num IS NOT NULL
Должно быть относительно просто настроить несколько строк или разные шаблоны или поместить это во встроенный UDF.