У меня есть строка '1,2,3,4,5,6,', я хочу получить результат в виде массива, например:

1
2
3
4
5

Я пробовал использовать функцию, а также преобразовал ее в xml.

У меня вопрос:

with cte1 (str1,str2) AS
(
SELECT SUBSTRING('1,2,3,4,5,6,',1,1) X,
SUBSTRING('1,2,3,4,5,6,',CHARINDEX(',','1,2,3,4,5,6,,') +1,LEN('1,2,3,4,5,6,')-2) Y
UNION all
SELECT SUBSTRING(str2,1,1) X ,SUBSTRING(str2,CHARINDEX(',',str2)+1,LEN(str2)-2) Y
FROM CTE1
WHERE SUBSTRING(str2,CHARINDEX(',',str2)+0,1) <> ' ' )
SELECT str1 FROM CTE1;

Что дает ожидаемый результат. но если я меняю строку, она дает случайные результаты, например:

with cte1 (str1,str2) AS
(
SELECT SUBSTRING('24,78,45,56,',1,1) X,
SUBSTRING('24,78,45,56,',CHARINDEX(',','24,78,45,56,') +1,LEN('24,78,45,56,')-2) Y
UNION all
SELECT SUBSTRING(str2,1,1) X ,SUBSTRING(str2,CHARINDEX(',',str2)+1,LEN(str2)-2) Y
FROM CTE1
WHERE SUBSTRING(str2,CHARINDEX(',',str2)+0,1) <> ' ' )
SELECT str1 FROM CTE1;

Результат:

2
7
4
5

enter image description here

3
Rains 25 Фев 2016 в 10:11

3 ответа

Лучший ответ

Это будет работать, только если строка похожа на '12,34,45,56....', т.е. строка содержит значения, разделенные запятыми двумя цифрами.

with cte1 (str1,str2) AS
(
 SELECT SUBSTRING('24,78,45,56,',1,2) X,
        SUBSTRING('24,78,45,56,',CHARINDEX(',','24,78,45,56,') +1,LEN('24,78,45,56,')-2) Y
 UNION all
 SELECT SUBSTRING(str2,1,2) X ,SUBSTRING(str2,CHARINDEX(',',str2)+1,LEN(str2)-2) Y
 FROM CTE1
 WHERE SUBSTRING(str2,CHARINDEX(',',str2)+0,2) <> ' ' )
 SELECT str1 FROM CTE1;

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

Определение функции как это

CREATE FUNCTION SplitItem( @ItemIDs VARCHAR(MAX))
RETURNS @ItemTable TABLE ( Item VARCHAR(200) )
AS 
BEGIN
    DECLARE @Item VARCHAR(200)
    DECLARE @Index INT

    WHILE LEN(@ItemIDs) <> 0 
        BEGIN
            SET @Index = PATINDEX('%,%', @ItemIDs)
            IF @Index > 0 
                BEGIN
                    SET @Item = SUBSTRING(@ItemIDs, 1, @Index - 1) 
                    SET @ItemIDs = RIGHT(@ItemIDs, LEN(@ItemIDs) - @Index)
                    INSERT  INTO @ItemTable
                    VALUES  ( @Item )
                END
            ELSE 
                BEGIN
                    BREAK
                END
        END
    SET @Item = @ItemIDs 
    INSERT  INTO @ItemTable
    VALUES  ( @Item )

    RETURN
END

И используйте эту функцию как это

SELECT Item 
FROM SplitItem('1,2,3,44,55,66,77')

Это даст такой результат

1 2 3 44 55 66 77

0
Jaydip Jadhav 25 Фев 2016 в 07:55

Вы можете сделать что-то вроде этого:

DECLARE @string NVARCHAR(MAX) =  '1,2,3,4,5,6,',
        @xml xml

select @xml = cast('<d><q>'+REPLACE(@string,',','</q><q>')+'</q></d>' as xml)

SELECT n.v.value('.','nvarchar(2)')
FROM @xml.nodes('/d/q') AS n(v);

Результат:

----
1
2
3
4
5
6


(7 row(s) affected)
0
gofr1 25 Фев 2016 в 12:18

Вы можете использовать рекурсивный CTE

Declare @list NVARCHAR(MAX) = '1,2,3,4,5'
DECLARE @length INT = LEN(@list) + 1;

   WITH a AS
   (
       SELECT
           [start] = 1,
           [end]   = COALESCE(NULLIF(CHARINDEX(',', 
                       @List, 1), 0), @length),
           [value] = SUBSTRING(@list, 1, 
                     COALESCE(NULLIF(CHARINDEX(',', 
                       @List, 1), 0), @length) - 1)
       UNION ALL
       SELECT
           [start] = CONVERT(INT, [end]) + 1,
           [end]   = COALESCE(NULLIF(CHARINDEX(',', 
                       @list, [end] + 1), 0), @length),
           [value] = SUBSTRING(@list, [end] + 1, 
                     COALESCE(NULLIF(CHARINDEX(',', 
                       @list, [end] + 1), 0), @length)-[end]-1)
       FROM a
       WHERE [end] < @length
   )
    SELECT [value]
   FROM a
   WHERE LEN([value]) > 0
   OPTION (MAXRECURSION 0);
0
Jakub Szumiato 25 Фев 2016 в 07:28