вторник, 6 августа 2013 г.

И снова о парсинге строк в SQL

В одном из своих предыдущих постов я уже приводил пример как распарсить строку. Теперь хочу поделиться еще одним способом парсинга строки:
  1. DECLARE @string NVARCHAR(10) = 'a,b,c'
  2. DECLARE @delimiter NVARCHAR(1) = ',';
  3.  
  4. WITH ToTable([START], [END]) AS (
  5. SELECT 1 AS [START]
  6. ,CAST(CHARINDEX(@delimiter, @string) AS INT) AS [END]
  7. UNION ALL
  8. SELECT CAST([END] + 1 AS INT)
  9. ,CAST(CHARINDEX(@delimiter, @string, [END] + 1) AS INT)
  10. FROM ToTable
  11. WHERE [END] > 0
  12. )
  13. SELECT SUBSTRING(@string, [START],
  14. CASE WHEN [END] > 0 THEN [END] - [START] ELSE LEN(@string) END) AS [Words]
  15. FROM ToTable
Теперь о самом коде:
- первые две строчки строка, которую нужно распарсить и наш разделитель соответственно;
- в строчках с 4 по 12 мы с помощью CTE создаем таблицу ToTable c двумя столбцами start и end, в которые записываем "координаты" на основании которых будем вырезать из искомой строки наши значения (в столбце start номер позиции в строке начала значения, а в столбце end номер позиции в строке окончания значения), т.е. для нашей строки 'a,b,c' мы получим следующую таблицу:

- в строчках 13-15 мы на основании таблицы ToTable с помощью функции SUBSTRING (куда мы и будем подставлять необходимые значения начала и конца подстроки с нашими значениями) вырезаем наши значения.

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

Полезные ссылки
- CTE (Common Table Expressions)
- функции для работы со строками

4 комментария:

  1. Очень полезный запрос!Спасибо большое за такое разностороннее решение проблемы парсинга. Внесу свои "три копейки": здесь опечатка в имени переменной DECLARE @delimiter, а также в третьей строке необходимо добавить ";" - без нее не работает.

    ОтветитьУдалить
    Ответы
    1. Спасибо за комментарий и найденные опечатки :) Подправил пост.

      Удалить
  2. Этот комментарий был удален автором.

    ОтветитьУдалить
  3. Из этого можно сделать табличную функцию:

    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO

    CREATE FUNCTION [dbo].[fnc_ExplodeString] (@string varchar(MAX), @delimiter varchar(MAX))
    RETURNS @RESULT TABLE (Substrings varchar(MAX))
    AS
    BEGIN
    WITH ToTable([START], [END]) AS
    (
    SELECT
    1 AS [START],
    CAST(CHARINDEX(@delimiter, @string) AS INT) AS [END]
    UNION ALL
    SELECT
    CAST([END] + LEN(@delimiter) AS INT),
    CAST(CHARINDEX(@delimiter, @string, [END] + LEN(@delimiter)) AS INT)
    FROM
    ToTable
    WHERE
    [END] > 0
    )
    INSERT INTO @RESULT
    SELECT
    SUBSTRING
    (
    @string,
    [START],
    CASE
    WHEN [END] > 0 THEN [END] - [START]
    ELSE LEN(@string)
    END
    ) AS [Words]
    FROM
    ToTable
    OPTION
    (MAXRECURSION 0)

    RETURN
    END
    GO

    ОтветитьУдалить