문제

를 사용하여 SQL Server,어떻게 분할 문자열을 그래서 액세스할 수 있는 항목 x?

String"Hello 존 스미스".는 방법은 문자열을 분할하여 공간에 액세스템 인덱스에 있는 1 을 반환해야 합니다"John"?

도움이 되었습니까?

해결책

을 찾을 수 있습니다 솔루션 SQL 사용자 정의 기능을 분석하는 문자열로 구분 도움이 됩니다(서 코드는 프로젝트).

이 사용할 수 있습니다 간단한 논리:

Declare @products varchar(200) = '1|20|3|343|44|6|8765'
Declare @individual varchar(20) = null

WHILE LEN(@products) > 0
BEGIN
    IF PATINDEX('%|%', @products) > 0
    BEGIN
        SET @individual = SUBSTRING(@products,
                                    0,
                                    PATINDEX('%|%', @products))
        SELECT @individual

        SET @products = SUBSTRING(@products,
                                  LEN(@individual + '|') + 1,
                                  LEN(@products))
    END
    ELSE
    BEGIN
        SET @individual = @products
        SET @products = NULL
        SELECT @individual
    END
END

다른 팁

믿지 않는 SQL Server 장에서 분리 기능,그 이외의 다른 UDF 만 다른 답을 내가 알고있는 대부분 PARSENAME 기능:

SELECT PARSENAME(REPLACE('Hello John Smith', ' ', '.'), 2) 

PARSENAME 문자열을 분할하고 기간에 문자입니다.그것은 수로의 두 번째 인수,그리고 그 숫자를 지정하는 세그먼트는 문자열을 반환(일부터 다시 전면).

SELECT PARSENAME(REPLACE('Hello John Smith', ' ', '.'), 3)  --return Hello

분명 문제가 될 때 문자열이 이미 포함합니다.저는 여전히 사용하는 UDF 최선의 방법입니다 다른 방법은?

첫째,생성 기능(사용 CTE,일반적인 표현을 필요로에 대한 임시 테이블)

 create function dbo.SplitString 
    (
        @str nvarchar(4000), 
        @separator char(1)
    )
    returns table
    AS
    return (
        with tokens(p, a, b) AS (
            select 
                1, 
                1, 
                charindex(@separator, @str)
            union all
            select
                p + 1, 
                b + 1, 
                charindex(@separator, @str, b + 1)
            from tokens
            where b > 0
        )
        select
            p-1 zeroBasedOccurance,
            substring(
                @str, 
                a, 
                case when b > 0 then b-a ELSE 4000 end) 
            AS s
        from tokens
      )
    GO

그때로 그것을 사용하여 어떤 테이블(또는 수정은 그것에 맞도록 귀하의 기존 저장 proc)은 이렇습니다.

select s 
from dbo.SplitString('Hello John Smith', ' ')
where zeroBasedOccurance=1

업데이트

이전 버전은 실패를 입력 문자열 4000 습니다.이 버전은 처리의 제한:

create function dbo.SplitString 
(
    @str nvarchar(max), 
    @separator char(1)
)
returns table
AS
return (
with tokens(p, a, b) AS (
    select 
        cast(1 as bigint), 
        cast(1 as bigint), 
        charindex(@separator, @str)
    union all
    select
        p + 1, 
        b + 1, 
        charindex(@separator, @str, b + 1)
    from tokens
    where b > 0
)
select
    p-1 ItemIndex,
    substring(
        @str, 
        a, 
        case when b > 0 then b-a ELSE LEN(@str) end) 
    AS s
from tokens
);

GO

사용법 동일하게 유지됩니다.

의 대부분은 여기에 솔루션을 사용하는 동안 루프 또는 재귀 Cte.세트-기반 접근 방법이 될 우수한 약속:

CREATE FUNCTION [dbo].[SplitString]
    (
        @List NVARCHAR(MAX),
        @Delim VARCHAR(255)
    )
    RETURNS TABLE
    AS
        RETURN ( SELECT [Value] FROM 
          ( 
            SELECT 
              [Value] = LTRIM(RTRIM(SUBSTRING(@List, [Number],
              CHARINDEX(@Delim, @List + @Delim, [Number]) - [Number])))
            FROM (SELECT Number = ROW_NUMBER() OVER (ORDER BY name)
              FROM sys.all_objects) AS x
              WHERE Number <= LEN(@List)
              AND SUBSTRING(@Delim + @List, [Number], LEN(@Delim)) = @Delim
          ) AS y
        );

더 많은에 분할 기능을 이유는(증거)하는 동안 루프 및 재귀 Cte 지 않는 스케일,그리고 더 나은 대안이 있는 경우에,분할 문자열에 오는 응용 프로그램에서 레이어:

SQL Server2016 또는 위 하지만,당신이 봐야 STRING_SPLIT()STRING_AGG():

을 활용할 수 있습니다 숫자를 표하는 문자열을 분석.

물리 숫자의 테이블:

    create table dbo.Numbers (N int primary key);
    insert into dbo.Numbers
        select top 1000 row_number() over(order by number) from master..spt_values
    go

테스트는 테이블과 함께 행 1000000

    create table #yak (i int identity(1,1) primary key, array varchar(50))

    insert into #yak(array)
        select 'a,b,c' from dbo.Numbers n cross join dbo.Numbers nn
    go

생성 기능

    create function [dbo].[ufn_ParseArray]
        (   @Input      nvarchar(4000), 
            @Delimiter  char(1) = ',',
            @BaseIdent  int
        )
    returns table as
    return  
        (   select  row_number() over (order by n asc) + (@BaseIdent - 1) [i],
                    substring(@Input, n, charindex(@Delimiter, @Input + @Delimiter, n) - n) s
            from    dbo.Numbers
            where   n <= convert(int, len(@Input)) and
                    substring(@Delimiter + @Input, n, 1) = @Delimiter
        )
    go

사용(출력 3mil 행 40s 터)

    select * 
    from #yak 
    cross apply dbo.ufn_ParseArray(array, ',', 1)

정리

    drop table dbo.Numbers;
    drop function  [dbo].[ufn_ParseArray]

성능 여기지 않은 놀라운지만,함수를 호출만 행 테이블은 가장 좋은 생각이 아니다.수행하는 경우에는 문자열을 분 이상 많은 행 피하는 기능.

이 질문은 지에 대한 문자열을 분리 접근 방식, 대만 을 얻는 방법 n 번째 요소.

모든 답변을 여기에서 하고 있는 어떤 종류의 문자열을 나누기를 사용하여 재귀, CTEs,여러 개 CHARINDEX, REVERSEPATINDEX, 발명,기능,전화 CLR 방법,숫자,테이블 CROSS APPLYs...대부분의 답변들은 줄의 코드입니다.

하지만-만약 당신이 정말로 것보다 더 많은 아무것도 원하지 않는 접근 방식을 얻을 수 n 번째 요소 -와 같이 수행할 수 있습니다 실제 중 하나-라이너, 없는 UDF,심지어 하위를 선택하...추가 이점: 유 안전

부 2 공백으로 구분하여:

DECLARE @input NVARCHAR(100)=N'part1 part2 part3';
SELECT CAST(N'<x>' + REPLACE(@input,N' ',N'</x><x>') + N'</x>' AS XML).value('/x[2]','nvarchar(max)')

물론 변수를 사용할 수 있습니다 에 대한 구분 기호 및 위치(사용 sql:column 검색에 직접 위치에서 쿼리의 값):

DECLARE @dlmt NVARCHAR(10)=N' ';
DECLARE @pos INT = 2;
SELECT CAST(N'<x>' + REPLACE(@input,@dlmt,N'</x><x>') + N'</x>' AS XML).value('/x[sql:variable("@pos")][1]','nvarchar(max)')

하는 경우 문자열을 포함 할 수 있습니다 자금성자 (특히 중 하나이 &><다),당신은 여전히 그것을 할 수 있는 이 방법입니다.사 FOR XML PATH 에서 당신의 첫 번째 문자열을 모두 교체하는 금지된 문자와 피팅을 탈출 시퀀스를 사용한다.

그것은 아주 특별한 경우-또는- 귀하의 기호는 세미콜론.이 경우에는 나는 대체 구분하는 첫 번째'#DLMT#',그리고 대체 이 XML 태그를 마지막으로:

SET @input=N'Some <, > and &;Other äöü@€;One more';
SET @dlmt=N';';
SELECT CAST(N'<x>' + REPLACE((SELECT REPLACE(@input,@dlmt,'#DLMT#') AS [*] FOR XML PATH('')),N'#DLMT#',N'</x><x>') + N'</x>' AS XML).value('/x[sql:variable("@pos")][1]','nvarchar(max)');

업데이트에 대한 SQL-Server2016+

유감스럽게도 개발자들은 잊어 반환하는 부분의 인덱스 STRING_SPLIT.그러나 사용하여 SQL-Server2016+가 OPENJSON.

문서 국어

때 OPENJSON 분석 JSON 배열이 반환 요소의 인덱스 JSON 텍스트로 키가 있습니다.

문자열 1,2,3 필요 아무것도보다 더 많은 괄호: [1,2,3].
의 문자열과 같은 단어 this is an example["this","is","an"," example"].
이들은 아주 쉬운 문자열 작업입니다.단지 그것을 시도 아웃:

DECLARE @str VARCHAR(100)='Hello John Smith';

SELECT [value]
FROM OPENJSON('["' + REPLACE(@str,' ','","') + '"]')
WHERE [key]=1 --zero-based!

여기에는 UDF 는 그것을 할 것입니다.그것을 반환합니다 테이블의 구분 값을 시도하지 않은 모든 시나리오에서 그만의 예로 작동합니다.


CREATE FUNCTION SplitString 
(
    -- Add the parameters for the function here
    @myString varchar(500),
    @deliminator varchar(10)
)
RETURNS 
@ReturnTable TABLE 
(
    -- Add the column definitions for the TABLE variable here
    [id] [int] IDENTITY(1,1) NOT NULL,
    [part] [varchar](50) NULL
)
AS
BEGIN
        Declare @iSpaces int
        Declare @part varchar(50)

        --initialize spaces
        Select @iSpaces = charindex(@deliminator,@myString,0)
        While @iSpaces > 0

        Begin
            Select @part = substring(@myString,0,charindex(@deliminator,@myString,0))

            Insert Into @ReturnTable(part)
            Select @part

    Select @myString = substring(@mystring,charindex(@deliminator,@myString,0)+ len(@deliminator),len(@myString) - charindex(' ',@myString,0))


            Select @iSpaces = charindex(@deliminator,@myString,0)
        end

        If len(@myString) > 0
            Insert Into @ReturnTable
            Select @myString

    RETURN 
END
GO

당신은 그것을 다음과 같다:


Select * From SplitString('Hello John Smith',' ')

편집:업데이트된 솔루션을 처리하 delimters 로 len>1 로 in:


select * From SplitString('Hello**John**Smith','**')

여기에 내가 포스트는 간단한 방법으로 솔루션

CREATE FUNCTION [dbo].[split](
          @delimited NVARCHAR(MAX),
          @delimiter NVARCHAR(100)
        ) RETURNS @t TABLE (id INT IDENTITY(1,1), val NVARCHAR(MAX))
        AS
        BEGIN
          DECLARE @xml XML
          SET @xml = N'<t>' + REPLACE(@delimited,@delimiter,'</t><t>') + '</t>'

          INSERT INTO @t(val)
          SELECT  r.value('.','varchar(MAX)') as item
          FROM  @xml.nodes('/t') as records(r)
          RETURN
        END


실행하여 같은 기능이

  select * from dbo.split('Hello John Smith',' ')

내 생각에 너희들은 그것을 만드는 방법이 너무 복잡합니다.들 CLR UDF 과될 수행합니다.

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Collections.Generic;

public partial class UserDefinedFunctions {
  [SqlFunction]
  public static SqlString SearchString(string Search) {
    List<string> SearchWords = new List<string>();
    foreach (string s in Search.Split(new char[] { ' ' })) {
      if (!s.ToLower().Equals("or") && !s.ToLower().Equals("and")) {
        SearchWords.Add(s);
      }
    }

    return new SqlString(string.Join(" OR ", SearchWords.ToArray()));
  }
};

에 대해 무엇을 사용하여 stringvalues() 문?

DECLARE @str varchar(max)
SET @str = 'Hello John Smith'

DECLARE @separator varchar(max)
SET @separator = ' '

DECLARE @Splited TABLE(id int IDENTITY(1,1), item varchar(max))

SET @str = REPLACE(@str, @separator, '''),(''')
SET @str = 'SELECT * FROM (VALUES(''' + @str + ''')) AS V(A)' 

INSERT INTO @Splited
EXEC(@str)

SELECT * FROM @Splited

결정을 달성했다.

id  item
1   Hello
2   John
3   Smith

내가 사용하는 응답의 프레드릭 하지만 이 작동하지 않았다에서 SQL Server2005

나는 그것을 수정하고 나를 사용하여 selectunion all 그리고 작동

DECLARE @str varchar(max)
SET @str = 'Hello John Smith how are you'

DECLARE @separator varchar(max)
SET @separator = ' '

DECLARE @Splited table(id int IDENTITY(1,1), item varchar(max))

SET @str = REPLACE(@str, @separator, ''' UNION ALL SELECT ''')
SET @str = ' SELECT  ''' + @str + '''  ' 

INSERT INTO @Splited
EXEC(@str)

SELECT * FROM @Splited

그 결과 세입니다:

id  item
1   Hello
2   John
3   Smith
4   how
5   are
6   you

이 패턴 자동할 수 있는 일반화

Convert(xml,'<n>'+Replace(FIELD,'.','</n><n>')+'</n>').value('(/n[INDEX])','TYPE')
                          ^^^^^                                   ^^^^^     ^^^^

참고 분야, INDEX유형.

일부 테이블을 식별자를 가진아

sys.message.1234.warning.A45
sys.message.1235.error.O98
....

다음을 작성할 수 있습니다

SELECT Source         = q.value('(/n[1])', 'varchar(10)'),
       RecordType     = q.value('(/n[2])', 'varchar(20)'),
       RecordNumber   = q.value('(/n[3])', 'int'),
       Status         = q.value('(/n[4])', 'varchar(5)')
FROM   (
         SELECT   q = Convert(xml,'<n>'+Replace(fieldName,'.','</n><n>')+'</n>')
         FROM     some_TABLE
       ) Q

분할 및 주물의 모든 부분입니다.

는 경우의 데이터베이스에 호환성의 수준 130 또는 더 높은 다음을 사용할 수 있습니다 STRING_SPLIT 과 함께 작 오프셋을 가져옵 절을 얻는 특정 항목으로 인덱스입니다.

을 얻은 항목에 index N (영반),사용할 수 있습니다 다음 코드

SELECT value
FROM STRING_SPLIT('Hello John Smith',' ')
ORDER BY (SELECT NULL)
OFFSET N ROWS
FETCH NEXT 1 ROWS ONLY

확인 호환성의 수준의 데이터베이스, 실행 코드:

SELECT compatibility_level  
FROM sys.databases WHERE name = 'YourDBName';

에 대한 솔루션에 순고 아래 나를 위해 작동 합니다.Ref.

당신은 함수를 호출하는 다음과 같다:

SELECT * FROM dbo.split('ram shyam hari gopal',' ')

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE FUNCTION [dbo].[Split](@String VARCHAR(8000), @Delimiter CHAR(1))       
RETURNS @temptable TABLE (items VARCHAR(8000))       
AS       
BEGIN       
    DECLARE @idx INT       
    DECLARE @slice VARCHAR(8000)        
    SELECT @idx = 1       
    IF len(@String)<1 OR @String IS NULL  RETURN       
    WHILE @idx!= 0       
    BEGIN       
        SET @idx = charindex(@Delimiter,@String)       
        IF @idx!=0       
            SET @slice = LEFT(@String,@idx - 1)       
        ELSE       
            SET @slice = @String       
        IF(len(@slice)>0)  
            INSERT INTO @temptable(Items) VALUES(@slice)       
        SET @String = RIGHT(@String,len(@String) - @idx)       
        IF len(@String) = 0 break       
    END   
    RETURN       
END

아직 다른 얻 n 번째 부분의 문자열음 delimeter 기능:

create function GetStringPartByDelimeter (
    @value as nvarchar(max),
    @delimeter as nvarchar(max),
    @position as int
) returns NVARCHAR(MAX) 
AS BEGIN
    declare @startPos as int
    declare @endPos as int
    set @endPos = -1
    while (@position > 0 and @endPos != 0) begin
        set @startPos = @endPos + 1
        set @endPos = charindex(@delimeter, @value, @startPos)

        if(@position = 1) begin
            if(@endPos = 0)
                set @endPos = len(@value) + 1

            return substring(@value, @startPos, @endPos - @startPos)
        end

        set @position = @position - 1
    end

    return null
end

고 사용:

select dbo.GetStringPartByDelimeter ('a;b;c;d;e', ';', 3)

는 반환합니다:

c

이것을 보십시오:

CREATE function [SplitWordList]
(
 @list varchar(8000)
)
returns @t table 
(
 Word varchar(50) not null,
 Position int identity(1,1) not null
)
as begin
  declare 
    @pos int,
    @lpos int,
    @item varchar(100),
    @ignore varchar(100),
    @dl int,
    @a1 int,
    @a2 int,
    @z1 int,
    @z2 int,
    @n1 int,
    @n2 int,
    @c varchar(1),
    @a smallint
  select 
    @a1 = ascii('a'),
    @a2 = ascii('A'),
    @z1 = ascii('z'),
    @z2 = ascii('Z'),
    @n1 = ascii('0'),
    @n2 = ascii('9')
  set @ignore = '''"'
  set @pos = 1
  set @dl = datalength(@list)
  set @lpos = 1
  set @item = ''
  while (@pos <= @dl) begin
    set @c = substring(@list, @pos, 1)
    if (@ignore not like '%' + @c + '%') begin
      set @a = ascii(@c)
      if ((@a >= @a1) and (@a <= @z1))  
        or ((@a >= @a2) and (@a <= @z2))
        or ((@a >= @n1) and (@a <= @n2))
      begin
        set @item = @item + @c
      end else if (@item > '') begin
        insert into @t values (@item)
        set @item = ''
      end
    end 
    set @pos = @pos + 1
  end
  if (@item > '') begin
    insert into @t values (@item)
  end
  return
end

테스트는 이를 다음과 같이 설명합니다:

select * from SplitWordList('Hello John Smith')

다음 예에서 사용하는 재귀 CTE

업데이트 18.09.2013

CREATE FUNCTION dbo.SplitStrings_CTE(@List nvarchar(max), @Delimiter nvarchar(1))
RETURNS @returns TABLE (val nvarchar(max), [level] int, PRIMARY KEY CLUSTERED([level]))
AS
BEGIN
;WITH cte AS
 (
  SELECT SUBSTRING(@List, 0, CHARINDEX(@Delimiter,  @List + @Delimiter)) AS val,
         CAST(STUFF(@List + @Delimiter, 1, CHARINDEX(@Delimiter, @List + @Delimiter), '') AS nvarchar(max)) AS stval, 
         1 AS [level]
  UNION ALL
  SELECT SUBSTRING(stval, 0, CHARINDEX(@Delimiter, stval)),
         CAST(STUFF(stval, 1, CHARINDEX(@Delimiter, stval), '') AS nvarchar(max)),
         [level] + 1
  FROM cte
  WHERE stval != ''
  )
  INSERT @returns
  SELECT REPLACE(val, ' ','' ) AS val, [level]
  FROM cte
  WHERE val > ''
  RETURN
END

데모 SQLFiddle



    Alter Function dbo.fn_Split
    (
    @Expression nvarchar(max),
    @Delimiter  nvarchar(20) = ',',
    @Qualifier  char(1) = Null
    )
    RETURNS @Results TABLE (id int IDENTITY(1,1), value nvarchar(max))
    AS
    BEGIN
       /* USAGE
            Select * From dbo.fn_Split('apple pear grape banana orange honeydew cantalope 3 2 1 4', ' ', Null)
            Select * From dbo.fn_Split('1,abc,"Doe, John",4', ',', '"')
            Select * From dbo.fn_Split('Hello 0,"&""&&&&', ',', '"')
       */

       -- Declare Variables
       DECLARE
          @X     xml,
          @Temp  nvarchar(max),
          @Temp2 nvarchar(max),
          @Start int,
          @End   int

       -- HTML Encode @Expression
       Select @Expression = (Select @Expression For XML Path(''))

       -- Find all occurences of @Delimiter within @Qualifier and replace with |||***|||
       While PATINDEX('%' + @Qualifier + '%', @Expression) > 0 AND Len(IsNull(@Qualifier, '')) > 0
       BEGIN
          Select
             -- Starting character position of @Qualifier
             @Start = PATINDEX('%' + @Qualifier + '%', @Expression),
             -- @Expression starting at the @Start position
             @Temp = SubString(@Expression, @Start + 1, LEN(@Expression)-@Start+1),
             -- Next position of @Qualifier within @Expression
             @End = PATINDEX('%' + @Qualifier + '%', @Temp) - 1,
             -- The part of Expression found between the @Qualifiers
             @Temp2 = Case When @End < 0 Then @Temp Else Left(@Temp, @End) End,
             -- New @Expression
             @Expression = REPLACE(@Expression,
                                   @Qualifier + @Temp2 + Case When @End < 0 Then '' Else @Qualifier End,
                                   Replace(@Temp2, @Delimiter, '|||***|||')
                           )
       END

       -- Replace all occurences of @Delimiter within @Expression with '</fn_Split><fn_Split>'
       -- And convert it to XML so we can select from it
       SET
          @X = Cast('<fn_Split>' +
                    Replace(@Expression, @Delimiter, '</fn_Split><fn_Split>') +
                    '</fn_Split>' as xml)

       -- Insert into our returnable table replacing '|||***|||' back to @Delimiter
       INSERT @Results
       SELECT
          "Value" = LTRIM(RTrim(Replace(C.value('.', 'nvarchar(max)'), '|||***|||', @Delimiter)))
       FROM
          @X.nodes('fn_Split') as X(C)

       -- Return our temp table
       RETURN
    END

나는 그것의 오래된 질문이지만,제가 생각하는 어떤 하나의 혜택을 누릴 수 있습 나의 솔루션입니다.

select 
SUBSTRING(column_name,1,CHARINDEX(' ',column_name,1)-1)
,SUBSTRING(SUBSTRING(column_name,CHARINDEX(' ',column_name,1)+1,LEN(column_name))
    ,1
    ,CHARINDEX(' ',SUBSTRING(column_name,CHARINDEX(' ',column_name,1)+1,LEN(column_name)),1)-1)
,SUBSTRING(SUBSTRING(column_name,CHARINDEX(' ',column_name,1)+1,LEN(column_name))
    ,CHARINDEX(' ',SUBSTRING(column_name,CHARINDEX(' ',column_name,1)+1,LEN(column_name)),1)+1
    ,LEN(column_name))
from table_name

SQL 바이올린

장점:

  • 그것을 분리하는 모든 3-문자에 의해''.
  • 한지를 사용하는 동안 반복,그것은 성능을 감소합니다.
  • 할 필요가 없을 피벗로 모든 결과 하위 문자열로 표시됩 하나 줄

제한 사항:

  • 하나 알아야 합 총 no.의 공간(하위 문자열).

참고:이 솔루션을 줄 수 있는 하위 문자열을 N.

을 극복하고 우수한 품질의 제품을 공급할 수 있 다음 사용 ref.

그러나 다시 위의 솔루션 사용 될 수 없습니 테이블에서(전문지 않았을 사용할 수 있다).

다시는 이 솔루션을 도울 수 있는 일입니다.

업데이트: 의 경우 레코드>50000 지 는 것이 좋습LOOPS 으로 그것이 저하 성능

거의 모든 다른 답변을 분할 코드 교체하는 문자열이 분리되고 있는 폐기물 CPU 사이클을 수행한 불필요한 메모리 할당입니다.

나는 훨씬 더 좋은 방법은 문자열을 분할 여기: http://www.digitalruby.com/split-string-sql-server/

는 코드는 다음과 같습니다:

SET NOCOUNT ON

-- You will want to change nvarchar(MAX) to nvarchar(50), varchar(50) or whatever matches exactly with the string column you will be searching against
DECLARE @SplitStringTable TABLE (Value nvarchar(MAX) NOT NULL)
DECLARE @StringToSplit nvarchar(MAX) = 'your|string|to|split|here'
DECLARE @SplitEndPos int
DECLARE @SplitValue nvarchar(MAX)
DECLARE @SplitDelim nvarchar(1) = '|'
DECLARE @SplitStartPos int = 1

SET @SplitEndPos = CHARINDEX(@SplitDelim, @StringToSplit, @SplitStartPos)

WHILE @SplitEndPos > 0
BEGIN
    SET @SplitValue = SUBSTRING(@StringToSplit, @SplitStartPos, (@SplitEndPos - @SplitStartPos))
    INSERT @SplitStringTable (Value) VALUES (@SplitValue)
    SET @SplitStartPos = @SplitEndPos + 1
    SET @SplitEndPos = CHARINDEX(@SplitDelim, @StringToSplit, @SplitStartPos)
END

SET @SplitValue = SUBSTRING(@StringToSplit, @SplitStartPos, 2147483647)
INSERT @SplitStringTable (Value) VALUES(@SplitValue)

SET NOCOUNT OFF

-- You can select or join with the values in @SplitStringTable at this point.

분할할 수 있습니다 string SQL 필요 없이 기능:

DECLARE @bla varchar(MAX)
SET @bla = 'BED40DFC-F468-46DD-8017-00EF2FA3E4A4,64B59FC5-3F4D-4B0E-9A48-01F3D4F220B0,A611A108-97CA-42F3-A2E1-057165339719,E72D95EA-578F-45FC-88E5-075F66FD726C'

-- http://stackoverflow.com/questions/14712864/how-to-query-values-from-xml-nodes
SELECT 
    x.XmlCol.value('.', 'varchar(36)') AS val 
FROM 
(
    SELECT 
    CAST('<e>' + REPLACE(@bla, ',', '</e><e>') + '</e>' AS xml) AS RawXml
) AS b 
CROSS APPLY b.RawXml.nodes('e') x(XmlCol);

을 지원해야 하는 경우에는 임의의 문자열(xml 특수 문자)

DECLARE @bla NVARCHAR(MAX)
SET @bla = '<html>unsafe & safe Utf8CharsDon''tGetEncoded ÄöÜ - "Conex"<html>,Barnes & Noble,abc,def,ghi'

-- http://stackoverflow.com/questions/14712864/how-to-query-values-from-xml-nodes
SELECT 
    x.XmlCol.value('.', 'nvarchar(MAX)') AS val 
FROM 
(
    SELECT 
    CAST('<e>' + REPLACE((SELECT @bla FOR XML PATH('')), ',', '</e><e>') + '</e>' AS xml) AS RawXml
) AS b 
CROSS APPLY b.RawXml.nodes('e') x(XmlCol); 

순수한 설정합 기반의 솔루션을 사용하여 TVF 과 재귀 CTE.수 JOINAPPLY 이 기능을 사용합니다.

create function [dbo].[SplitStringToResultSet] (@value varchar(max), @separator char(1))
returns table
as return
with r as (
    select value, cast(null as varchar(max)) [x], -1 [no] from (select rtrim(cast(@value as varchar(max))) [value]) as j
    union all
    select right(value, len(value)-case charindex(@separator, value) when 0 then len(value) else charindex(@separator, value) end) [value]
    , left(r.[value], case charindex(@separator, r.value) when 0 then len(r.value) else abs(charindex(@separator, r.[value])-1) end ) [x]
    , [no] + 1 [no]
    from r where value > '')

select ltrim(x) [value], [no] [index] from r where x is not null;
go

사용법:

select *
from [dbo].[SplitStringToResultSet]('Hello John Smith', ' ')
where [index] = 1;

결과:

value   index
-------------
John    1

로 시작 SQL Server2016string_split

DECLARE @string varchar(100) = 'Richard, Mike, Mark'

SELECT value FROM string_split(@string, ',')

현대적인 접근 방식을 사용하여 STRING_SPLIT, 이 필요합 SQL Server2016 습니다.

DECLARE @string varchar(100) = 'Hello John Smith'

SELECT
    ROW_NUMBER() OVER (ORDER BY value) AS RowNr,
    value
FROM string_split(@string, ' ')

결과:

RowNr   value
1       Hello
2       John
3       Smith

지금 그것을 얻을 수 th n 번째 요소에서 행 번호입니다.

아론은 베르트랑의 대답은 중대하다,그러나 결함이 있습니다.지 않는 정확하게 처리하는 공간으로 구분 기호(로의 예제에서는 원래 질문)이후 길이는 기능을 끄는 스트립 공간이 있습니다.

다음의 코드는,작은 조정을 허용하기 위하여 공간을 구분 기호:

CREATE FUNCTION [dbo].[SplitString]
(
    @List NVARCHAR(MAX),
    @Delim VARCHAR(255)
)
RETURNS TABLE
AS
    RETURN ( SELECT [Value] FROM 
      ( 
        SELECT 
          [Value] = LTRIM(RTRIM(SUBSTRING(@List, [Number],
          CHARINDEX(@Delim, @List + @Delim, [Number]) - [Number])))
        FROM (SELECT Number = ROW_NUMBER() OVER (ORDER BY name)
          FROM sys.all_objects) AS x
          WHERE Number <= LEN(@List)
          AND SUBSTRING(@Delim + @List, [Number], LEN(@Delim+'x')-1) = @Delim
      ) AS y
    );

여기에는 함수를 달성할 것입니다 질문의 목적을 분할 문자열에 액세스하는 항목 X:

CREATE FUNCTION [dbo].[SplitString]
(
   @List       VARCHAR(MAX),
   @Delimiter  VARCHAR(255),
   @ElementNumber INT
)
RETURNS VARCHAR(MAX)
AS
BEGIN

       DECLARE @inp VARCHAR(MAX)
       SET @inp = (SELECT REPLACE(@List,@Delimiter,'_DELMTR_') FOR XML PATH(''))

       DECLARE @xml XML
       SET @xml = '<split><el>' + REPLACE(@inp,'_DELMTR_','</el><el>') + '</el></split>'

       DECLARE @ret VARCHAR(MAX)
       SET @ret = (SELECT
              el = split.el.value('.','varchar(max)')
       FROM  @xml.nodes('/split/el[string-length(.)>0][position() = sql:variable("@elementnumber")]') split(el))

       RETURN @ret

END

사용법:

SELECT dbo.SplitString('Hello John Smith', ' ', 2)

결과:

John

간단한 솔루션에 대한 분석과 이름

DECLARE @Name varchar(10) = 'John Smith'

-- Get First Name
SELECT SUBSTRING(@Name, 0, (SELECT CHARINDEX(' ', @Name)))

-- Get Last Name
SELECT SUBSTRING(@Name, (SELECT CHARINDEX(' ', @Name)) + 1, LEN(@Name))

내 경우에는(그리고 많은 다른 사람이 그것을 보인...),나는 목록의 첫 번째와 마지막으로 구분하여 이름을 하나의 공간입니다.이 직접 사용할 수 있습니다 내기 위해 select 문을 분석합니다.

-- i.e. Get First and Last Name from a table of Full Names
SELECT SUBSTRING(FullName, 0, (SELECT CHARINDEX(' ', FullName))) as FirstName,
SUBSTRING(FullName, (SELECT CHARINDEX(' ', FullName)) + 1, LEN(FullName)) as LastName,
From FullNameTable

내가 알고 있는 그지만,저는 최근에 요구 사항과 이와 함께 아래 코드입니다.나는 선택의 여지가 없어를 사용하는 사용자 정의 기능입니다.이게 도움이 되었으면 좋겠습니다.

SELECT 
    SUBSTRING(
                SUBSTRING('Hello John Smith' ,0,CHARINDEX(' ','Hello John Smith',CHARINDEX(' ','Hello John Smith')+1)
                        ),CHARINDEX(' ','Hello John Smith'),LEN('Hello John Smith')
            )

론,광산되지 않는 모두 더 간단하지만 코드를 사용해 쪼개는 쉼표로 구분된 입력 변수를 개별적인 값을 넣어 테이블이 변수입니다.나는 확신할 수 있습이 약간 수정하여 분할에 따라 공간과 다음을 할 기본적인 선택에 대한 쿼리는 테이블보를 받을 변수의 결과입니다.

-- Create temporary table to parse the list of accounting cycles.
DECLARE @tblAccountingCycles table
(
    AccountingCycle varchar(10)
)

DECLARE @vchAccountingCycle varchar(10)
DECLARE @intPosition int

SET @vchAccountingCycleIDs = LTRIM(RTRIM(@vchAccountingCycleIDs)) + ','
SET @intPosition = CHARINDEX(',', @vchAccountingCycleIDs, 1)

IF REPLACE(@vchAccountingCycleIDs, ',', '') <> ''
BEGIN
    WHILE @intPosition > 0
    BEGIN
        SET @vchAccountingCycle = LTRIM(RTRIM(LEFT(@vchAccountingCycleIDs, @intPosition - 1)))
        IF @vchAccountingCycle <> ''
        BEGIN
            INSERT INTO @tblAccountingCycles (AccountingCycle) VALUES (@vchAccountingCycle)
        END
        SET @vchAccountingCycleIDs = RIGHT(@vchAccountingCycleIDs, LEN(@vchAccountingCycleIDs) - @intPosition)
        SET @intPosition = CHARINDEX(',', @vchAccountingCycleIDs, 1)
    END
END

개념은 거의 동일 합니다.다른 하나는 대안을 활용.NET 호환성 SQL Server 내에서 2005 년 자체입니다.할 수 있는 기본적으로 직접 작성한 간단한 방법이다.NET 는 것이 문자열을 분할하고 다음에 노출로 저장된 절차/기능입니다.

이것은 내가 한 것을 얻기 위해서 특정 토큰 문자열입니다.(에서 테스트 MSSQL2008)

첫째,만드는 다음과 같은 기능:(에서 발견:

CREATE FUNCTION dbo.SplitStrings_Moden
(
   @List NVARCHAR(MAX),
   @Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING AS
RETURN
  WITH E1(N)        AS ( SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 
                         UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 
                         UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1),
       E2(N)        AS (SELECT 1 FROM E1 a, E1 b),
       E4(N)        AS (SELECT 1 FROM E2 a, E2 b),
       E42(N)       AS (SELECT 1 FROM E4 a, E2 b),
       cteTally(N)  AS (SELECT 0 UNION ALL SELECT TOP (DATALENGTH(ISNULL(@List,1))) 
                         ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E42),
       cteStart(N1) AS (SELECT t.N+1 FROM cteTally t
                         WHERE (SUBSTRING(@List,t.N,1) = @Delimiter OR t.N = 0))
  SELECT Item = SUBSTRING(@List, s.N1, ISNULL(NULLIF(CHARINDEX(@Delimiter,@List,s.N1),0)-s.N1,8000))
    FROM cteStart s;

create FUNCTION dbo.getToken
(
@List NVARCHAR(MAX),
@Delimiter NVARCHAR(255),
@Pos int
)
RETURNS varchar(max)
as 
begin
declare @returnValue varchar(max);
select @returnValue = tbl.Item from (
select ROW_NUMBER() over (order by (select null)) as id, * from dbo.SplitStrings_Moden(@List, @Delimiter)
) as tbl
where tbl.id = @Pos
return @returnValue
end

당신은 그렇게 그것을 사용할 수 있습니다:

select dbo.getToken('1111_2222_3333_', '_', 1)

는 반환 1111

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top