Функция разделения SQL, которая обрабатывает строку с разделителем, появляющимся между квалификаторами текста?

Существует несколько функций разделения SQL, от управления циклом до использования команд xml и даже использования таблицы чисел. Я не нашел тот, который поддерживает текстовые квалификаторы.

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

Пример данных:

[email protected], "Sally \"Heat\" Jones" <[email protected]>, "Mark Jones" <[email protected]>, "Stone, Ron" <[email protected]>

Должен вернуть таблицу:

[email protected]
"Sally \"Heat\" Jones" <[email protected]>
"Mark Jones" <[email protected]>
"Stone, Ron" <[email protected]>

Я знаю, что это сложный запрос/функция, но любые предложения или рекомендации будут очень признательны.


person Ron    schedule 19.05.2010    source источник


Ответы (2)


Вот мое решение:

CREATE FUNCTION fnSplitString
(
    @input nvarchar(MAX) 
)
RETURNS @emails TABLE
(
    email nvarchar(MAX) 
)
AS
BEGIN

DECLARE @len int = LEN(@input)
DECLARE @pos int = 1;
DECLARE @start int = 1;
DECLARE @ignore bit = 0;
WHILE(@pos<=@len)
BEGIN

    DECLARE @ch nchar(1) = SUBSTRING(@input, @pos, 1);

    IF ( @ch = '"' or @ch = '''')
    BEGIN
        SET @ignore = 1 - @ignore;
    END

    IF (@ch = ',' AND @ignore = 0)
    BEGIN
        INSERT @emails VALUES (SUBSTRING(@input, @start, @pos-@start));
        SET @start = @pos+1;
    END

    SET @pos = @pos + 1;
END

IF (@start<>@pos)
BEGIN
    INSERT @emails VALUES (SUBSTRING(@input, @start, @pos-@start));
END

RETURN
END
GO

DECLARE @input nvarchar(max) = '[email protected], "Sally \"Heat\" Jones" <[email protected]>, "Mark Jones" <[email protected]>, "Stone, Ron" <[email protected]>';

select * from fnSplitString(@input)
person TTRider    schedule 12.08.2010

Это быстрое решение, и оно далеко не идеальное, у него нет стека, поэтому запятая внутри кавычек будет рассматриваться как разделитель.

alter function fnSplit
(
    @Delim char(1),
    @List nvarchar(4000)
)
returns table as
return
    with 
    Strings(PosIdx) as 
    (
        select 1 
        union all 
        select PosIdx + 1 from Strings where PosIdx < 4000
    )
    select
        ltrim(rtrim(substring(@List, PosIdx, charindex(@Delim, @List + @Delim, PosIdx) - PosIdx))) as value
    from   
        Strings
    where  
        PosIdx <= convert(int, len(@List))
    and substring(@Delim + @List, PosIdx, 1) = @Delim 
go
select * from fnSplit(',', '[email protected], "Sally \"Heat\" Jones" <[email protected]>, "Mark Jones" <[email protected]>, "Stone, Ron" <[email protected]>') 
    option (maxrecursion 0)
person Irawan Soetomo    schedule 20.05.2010
comment
Это явно не решение исходного вопроса. Я хотел бы разделить на , но не тогда, когда он появляется между двойными или одинарными кавычками. - person Ron; 20.05.2010