항목 x에 액세스 할 수 있도록 문자열을 어떻게 분할합니까?


493

SQL Server를 사용하여 항목 x에 액세스 할 수 있도록 문자열을 어떻게 분할합니까?

"Hello John Smith"문자열을 가져옵니다. 문자열을 공백으로 분할하고 인덱스 1에서 "John"을 반환해야하는 항목에 어떻게 액세스 할 수 있습니까?




4
가장 높은 여기에 대한 답변입니다 - 나를 위해 적어도 - 옛날 아주 오래된 오히려 밖으로 일자. 절차 적 위치 지정, 루프, 재귀, CLR, 함수, 여러 줄의 코드 ... "액티브"답변을 읽고 최신 접근 방식 을 찾는 것이 흥미로울 수 있습니다 .
Shnugo

더 최신의 접근 방식으로 새로운 답변을 추가했습니다. stackoverflow.com/a/49669994/632604
Gorgi Rankovski

시도 목록의 n 번째 요소를 가져옵니다 -> portosql.wordpress.com/2019/05/27/enesimo-elemento-lista
호세 디즈

답변:


191

구분 된 문자열을 구문 분석하는 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

1
SET @p_SourceText = RTRIM( LTRIM( @p_SourceText)) SET @w_Length = DATALENGTH( RTRIM( LTRIM( @p_SourceText)))하지 SET @p_SourceText = RTRIM( LTRIM( @p_SourceText)) SET @w_Length = DATALENGTH( @p_SourceText)?
Beth

12
@GateKiller이 솔루션은 유니 코드를 지원하지 않으며 하드 코딩 된 숫자 (18,3)를 사용하여 실행 가능한 "재사용 가능"기능이되지 않습니다.
Filip De Vos

4
이것은 작동하지만 많은 메모리를 할당하고 CPU를 낭비합니다.
jjxtra

2
SQL Server 2016부터는 STRING_SPLIT문자열을 분할하고 SELECT명령문이나 다른 곳 에서 사용할 수있는 1 열 테이블 결과를 반환하는 기본 제공 함수 가 있습니다.
qJake

제가 일하는 사람들이 2016 년이 아닌 것은 너무 나쁩니다. 그러나 그들이 구두에서 벗어나는 경우를 대비하여이 점을 명심하겠습니다. 중간에 훌륭한 솔루션. 함수로 구현하고 구분 기호를 인수로 추가했습니다.
Brandon Griffin

355

SQL Server에 내장 분할 기능이 있다고 생각하지 않으므로 UDF 이외의 다른 대답은 PARSENAME 함수를 납치하는 것입니다.

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

PARSENAME은 문자열을 가져 와서 마침표 문자로 분할합니다. 두 번째 인수로 숫자를 사용하며 그 숫자는 반환 할 문자열의 세그먼트를 지정합니다 (뒤에서 앞으로).

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

명백한 문제는 문자열에 이미 마침표가 포함되어있을 때입니다. 여전히 UDF를 사용하는 것이 가장 좋은 방법이라고 생각합니다. 다른 제안이 있습니까?


102
감사합니다 Saul ...이 솔루션은 실제로 실제 개발에 나쁜 솔루션임을 지적해야합니다. PARSENAME은 4 개의 파트 만 예상하므로 4 개 이상의 파트가있는 문자열을 사용하면 NULL을 리턴합니다. UDF 솔루션이 더 좋습니다.
Nathan Bedford

33
이것은 대단한 해킹이며, 실제 언어로 그렇게 간단한 것에 필요한 것 같은 것을 울게합니다.
Factor Mystic

36
인덱스가 "올바른"방식으로 작동하게하려면, 즉 1부터 시작하여 REVERSE로 도용을 도용했습니다. REVERSE (PARSENAME (REPLACE (REVERSE ( 'Hello John Smith'), '', '.') , 1))-Hello를 반환합니다.
NothingsImossible

3
@FactorMystic First Normal Form 에서는 단일 필드에 여러 값을 넣지 않아야합니다. 문자 그대로 RDBMS의 첫 번째 규칙입니다. SPLIT()함수는 가난한 데이터베이스 설계를 장려하기 때문에 공급되지 않으며, 데이터베이스는이 형식으로 저장된 데이터를 사용하도록 최적화되지 않습니다. RDBMS는 개발자가 처리 하지 않도록 설계된 어리석은 일을하도록 개발자에게 의무가 없습니다 . 정답은 항상 "40 년 전에 말했듯이 데이터베이스를 정규화하십시오"입니다. SQL이나 RDBMS 모두 나쁜 디자인에 대한 책임이 없습니다.
베이컨 비트

8
내가 이론에 동의하는 동안 @BaconBits, 실제로 이와 같은 도구는 당신 앞에 온 누군가가 생산 한 열악한 디자인을 정규화 할 때 유용합니다.
Tim Abell

110

먼저 함수를 작성하십시오 (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

그런 다음이 테이블을 테이블로 사용하거나 기존 저장 프로 시저에 맞게 수정하십시오.

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

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


14
우아하지만 재귀 깊이의 한계 때문에 100 요소에만 작동합니다.
Pking

4
@Pking, no, 기본값은 100(무한 루프 방지)입니다. 사용 MAXRECURSION 힌트는 재귀 수준의 번호 (정의하기 032767, 0"제한"입니다 - 서버를 분쇄 할 수있다). BTW는 PARSENAME보편적 인 것이므로 : 보다 ) +1
Michał Powaga

maxrecursion이 솔루션에 추가하면 이 질문과 그 대답을 명심하십시오 . Table-Valued-Function 내에서 CTE 옵션 을 설정하는 방법을maxrecursion 기억하십시오 .
Michał Powaga

구체적으로, Crisfole의 답변을 참조 하십시오 -그의 방법은 다소 느리지 만 대부분의 다른 옵션보다 간단합니다.
AHiggins

작은 점이지만 열 이름을 변경했기 때문에 사용법이 동일하게 유지되지 않으므로 s더 이상 정의되지 않습니다.
Tim Abell

62

여기에서 대부분의 솔루션은 while 루프 또는 재귀 적 CTE를 사용합니다. 공백 이외의 구분 기호를 사용할 수 있다면 세트 기반 접근 방식이 우수 할 것입니다.

CREATE FUNCTION [dbo].[SplitString]
    (
        @List NVARCHAR(MAX),
        @Delim VARCHAR(255)
    )
    RETURNS TABLE
    AS
        RETURN ( SELECT [Value], idx = RANK() OVER (ORDER BY n) FROM 
          ( 
            SELECT n = Number, 
              [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
        );

샘플 사용법 :

SELECT Value FROM dbo.SplitString('foo,bar,blat,foo,splunge',',')
  WHERE idx = 3;

결과 :

----
blat

idx함수에 인수로 원하는 것을 추가 할 수도 있지만 독자에게 연습으로 남겨 두겠습니다.

당신이 할 수없는 단지 기본 STRING_SPLIT기능 출력이 원래 목록의 순서로 렌더링 할 것이라는 보장이 없기 때문에, SQL 서버 2016에 추가했다. 즉, 3,6,1결과 를 전달 하면 순서 같을 있지만 그럴 있습니다 1,3,6. 내장 기능을 향상시키는 데 도움을 요청한 커뮤니티는 다음과 같습니다.

충분한 정 성적 피드백을 통해 실제로 다음과 같은 개선을 고려할 수 있습니다.

스플릿 함수에 대한 자세한 내용, while 루프 및 재귀 적 CTE가 확장되지 않는 이유 및 증명 및 애플리케이션 계층에서 문자열을 스플릿하는 경우 더 나은 대안 :

위의 SQL 서버 2016에,하지만 당신은 보라 STRING_SPLIT()STRING_AGG():


1
정답입니다. IMHO. 다른 답변 중 일부에는 SQL 재귀 제한 문제가 있지만이 경우에는 아닙니다. 매우 빠르고 간단한 구현. +2 버튼은 어디에 있습니까?
T-moty

5
내가 사용과 그대로이 함수를 시도했다 : select * from DBO.SplitString('Hello John smith', ' ');및 생성되는 출력했다 : 안녕하세요여보세요 LLO 보라 오 존 OHN HN N 스미스 MITH i 번째 번째 시간
wwmbes

2
@AaronBertrand GateKiller가 게시 한 원래 문제는 공백 구분 기호와 관련이 있습니다.
wwmbes

1
@ user1255933 해결되었습니다.
Aaron Bertrand

1
@Michael 네, 맞습니다. ALTER SCHEMA 권한이없는 경우 선택할 테이블이없고 SELECT 권한이없는 경우 선택할 수 없습니다. 언제든지 다른 사람 에게 함수를 작성 하도록 요청할 수 있습니다. . 또는 임시로도 tempdb와 같이 작성할 수있는 위치에 작성하십시오. 그리고 2016 년에는 STRING_SPLIT ()을 사용해야하며 어쨌든 자신을 만들어야하는 기능이 아닙니다.
Aaron Bertrand

38

숫자 테이블을 활용하여 문자열 구문 분석을 수행 할 수 있습니다.

물리 숫자 테이블을 만듭니다.

    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

사용법 (노트북에서 40 대 3mil 행 출력)

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

대청소

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

여기서 성능은 놀랍지 않지만 백만 행 테이블 이상의 함수를 호출하는 것이 가장 좋은 아이디어는 아닙니다. 문자열을 여러 행으로 나누면 함수를 피할 수 있습니다.


2
최고의 솔루션 IMO, 다른 솔루션에는 제한이 있습니다. 이것은 빠르며 많은 요소로 긴 문자열을 구문 분석 할 수 있습니다.
Pking

왜 내림차순으로 주문합니까? 세 항목이 있고 1부터 번호 매기기를 시작한 경우 첫 번째 항목은 3이며 마지막 항목은 1입니다 desc.
도끼-SOverflow와 함께

1
동의, 상승 방향으로보다 직관적입니다. 나는 DESC를 사용 parsename () 대회 다음 한
나단 Skerl

3
어떻게 작동하는지에 대한 설명
Tim Abell

구문 분석 할 최대 3 개 필드의 1 억 행에 대한 테스트에서 ufn_ParseArray는 25 분 후에 완료되지 않은 반면 REVERSE(PARSENAME(REPLACE(REVERSE('Hello John Smith'), ' ', '.'), 1)) @NothingsImpossible은 1.5 분 후에 완료되었습니다. @hello_earth 솔루션이 4 개 이상의 필드가있는 더 긴 문자열을 어떻게 비교합니까?
wwmbes

31

이 질문은 문자열 분할 방식 이 아니라 n 번째 요소를 얻는 방법에 관한 것 입니다.

여기에 모든 답이 재귀를 사용하여 문자열을 분할 어떤 종류의 일을하는, CTE이야, 배수 CHARINDEX, REVERSE그리고 PATINDEX, 발명 기능은 CLR 방법, 번호 테이블에 대한 호출 CROSS APPLY로 ... 대부분의 답변은 많은 코드를 다룹니다.

그러나 -n 번째 요소를 얻는 접근법 이상 을 정말로 원한다면 -이것은 실제로 하나의 라이너로 , UDF는없고, 하위 선택조차도 할 수 없으며 ... 추가 혜택 : type safe

공백으로 구분 된 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-Server 2016 이상 업데이트

유감스럽게도 개발자는로 부품 색인을 반환하는 것을 잊었습니다 STRING_SPLIT. 그러나 SQL-Server 2016+를 사용하면 JSON_VALUE및이 OPENJSON있습니다.

함께 JSON_VALUE우리는 인덱스 '배열과 위치에 전달할 수있다.

대한 문서가 명확하게 진술한다 :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';
DECLARE @position INT = 2;

--We can build the json-path '$[1]' using CONCAT
SELECT JSON_VALUE('["' + REPLACE(@str,' ','","') + '"]',CONCAT('$[',@position-1,']'));

-위치 안전 스트링 스플리터 ( 0부터 시작 )는 다음을 참조하십시오.

SELECT  JsonArray.[key] AS [Position]
       ,JsonArray.[value] AS [Part]
FROM OPENJSON('["' + REPLACE(@str,' ','","') + '"]') JsonArray

에서 이 게시물에 나는 다양한 접근 방법을 테스트하고, 발견 OPENJSON정말 빠릅니다. 유명한 "delimitedSplit8k ()"메소드보다 훨씬 빠릅니다.

업데이트 2-유형 안전 값 가져 오기

doubled를 사용하여 배열 내에서 배열을 사용할 수 있습니다 [[]]. 이것은 유형이 지정된 WITH-clause를 허용합니다 .

DECLARE  @SomeDelimitedString VARCHAR(100)='part1|1|20190920';

DECLARE @JsonArray NVARCHAR(MAX)=CONCAT('[["',REPLACE(@SomeDelimitedString,'|','","'),'"]]');

SELECT @SomeDelimitedString          AS TheOriginal
      ,@JsonArray                    AS TransformedToJSON
      ,ValuesFromTheArray.*
FROM OPENJSON(@JsonArray)
WITH(TheFirstFragment  VARCHAR(100) '$[0]'
    ,TheSecondFragment INT          '$[1]'
    ,TheThirdFragment  DATE         '$[2]') ValuesFromTheArray

다시 : 문자열에 금지 된 문자가 포함될 수 있다면 ... 하위 문자열을 간단히 래핑 할 수 <x><![CDATA[x<&>x]]></x>있습니다.
살만 A

@SalmanA, 예,-섹션도이 CDATA문제를 처리 할 수 ​​있습니다 ... 그러나 캐스트 후에는 사라졌습니다 ( text()암시 적 으로 탈출하도록 변경됨 ). 나는 후드 아래에서 마술을 좋아하지 않으므로 (SELECT 'Text with <&>' AS [*] FOR XML PATH(''))접근 방식을 선호합니다 . 이것은 나에게 깨끗해 보이고 어쨌든 발생합니다 ... ( CDATA 및 XML에 대해 더 자세히 알아보십시오 ).
Shnugo

22

여기 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',' ')

편집 : 다음과 같이 len> 1로 delimter를 처리하도록 솔루션이 업데이트되었습니다.


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

select * from dbo.ethos_SplitString_fn ( 'guy, wicks, was here', ',') id 부분에서 작동하지 않았습니다 .----------- -------------- -------------------------------------- 1 남자 2 심지
남자

2
인수에 후행 공백이있는 경우 올바른 숫자를 리턴하지 않으므로 len ()으로주의하십시오 (예 : len ( '-') = 2)
Rory

작동하지 않습니다 : select * from dbo.SplitString ( 'foo, foo test ,,,, foo', ',')
cbp

1
cbp.에 대한 수정. @myString = substring (@ mystring, @ iSpaces + len (@deliminator), len (@myString)-charindex (@ deliminator, @ myString, 0)) 선택
Alxwest

16

여기에 간단한 해결책을 게시합니다.

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',' ')

이 솔루션이 마음에 들었습니다. 결과 내에서 지정된 열을 기반으로 스칼라 값을 반환하도록 확장했습니다.
Alan

나는 이것을 사용하여 분리하기 위해 문자열에서 '&'로 화상을 입었다
KeithL

10

내 의견으로는 너희들은 그것을 너무 복잡하게 만들고있다. 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()));
  }
};

20
Visual Studio가 필요하고 서버에서 CLR을 활성화 한 다음 프로젝트를 생성 및 컴파일 한 다음 마지막으로 데이터베이스에 어셈블리를 추가해야하기 때문에 이것이 너무 복잡하다고 생각합니다. 그러나 여전히 흥미로운 답변입니다.
Guillermo Gutiérrez

3
@ guillegr123, 복잡 할 필요는 없습니다. SQLCLR 함수 및 procs의 라이브러리 인 SQL #을 다운로드하여 설치 (무료) 할 수 있습니다. SQLsharp.com 에서 얻을 수 있습니다 . 예, 저는 저자이지만 String_Split은 무료 버전에 포함되어 있습니다.
Solomon Rutzky

10

사용 string하고 values()진술하는 것은 어떻습니까?

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

1
난 당신의 대답을 사용하지만, 일을하지 않았다,하지만 난 수정이 모두, 내가 SQL 2005 사용하고 노조와 협력
천사

9

프레드릭의 대답을 사용하지만 SQL Server 2005에서는 작동하지 않았습니다.

나는 그것을 수정하고 select함께 사용 union 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

이것은 내가 SQL에서 본 적이 정말 훌륭합니다. 제 일을 위해 일했으며 감사합니다!
Abdurrahman I.

매우 깨끗하고 이해하기 쉽기 때문에 이것을 보았을 때 정말 흥분했지만 불행히도이 때문에 UDF에 넣을 수는 없습니다 EXEC. EXEC내재적으로 스토어드 프로 시저를 호출하므로 UDF에서 스토어드 프로 시저를 사용할 수 없습니다.
Kristen Hammack

이것은 완벽하게 작동합니다 !! 나는 여기에서 함수 (SplitStrings_Moden)를 사용하여 조사하고 있었다 : sqlperformance.com/2012/07/t-sql-queries/split-strings#comments이 작업 을 수행하고 데이터를 분할하고 반환하는 데 1 분 반이 걸렸 습니다. 4 개의 계좌 번호 만 사용하는 경우 행. 계정 번호의 데이터로 테이블에서 왼쪽 조인으로 버전을 테스트했으며 2 ~ 3 초가 걸렸습니다! 큰 차이와 완벽하게 작동합니다! 가능한 경우이 20 표를 드리겠습니다!
MattE

8

이 패턴은 잘 작동하며 일반화 할 수 있습니다

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

FIELD , INDEXTYPE을 참고하십시오 .

식별자가있는 테이블을 보자.

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

모든 부품 분리 및 주조.


이 솔루션은 여기에서 특정 유형으로 캐스트 할 수 있고 적당히 효율적입니다 (CLR이 여전히 가장 효율적이지만이 방법은 약 9 분 만에 8gb, 10 토큰, 10M 행 테이블을 처리합니다 (aws m3 서버, 4k iops) 프로비저닝 된 드라이브)
Andrew Hill

7

데이터베이스의 호환성 수준이 130 이상인 경우 STRING_SPLIT 함수와 OFFSET FETCH 절을 함께 사용하여 인덱스별로 특정 항목을 가져올 수 있습니다.

인덱스 N (0부터 시작)으로 항목을 가져 오려면 다음 코드를 사용할 수 있습니다.

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';

트릭은 OFFSET 1 ROWS에 있으며, 첫 번째 항목을 건너 뛰고 두 번째 항목을 반환합니다. 인덱스가 0을 기준으로하고 @X가 가져 오려는 항목 인덱스를 보유하는 변수 인 경우 OFFSET @X ROWS
Gorgi Rankovski

좋아, 전에 이것을 사용하지 않았다 ... 알아서 ... xml유형 안전 값을 가져올 수 있고 하위 쿼리가 필요하지 않기 때문에 여전히 -split 기반 접근 방식을 선호합니다 . 좋은 것. 내 편에서 +1
Shnugo

3
여기서 문제는 STRING_SPLIT가 반환 된 결과의 순서를 보장하지 않는다는 것입니다. 따라서 귀하의 항목 1은 내 항목 1 일 수도 있고 아닐 수도 있습니다.
user1443098

@GorgiRankovski, STRING_SPLITv2016 +의 요구 사항 사용 . 이 경우에는 훨씬 더 사용하는 것입니다 OPENJSONJSON_VALUE. 내 답변
Shnugo

6

나는 그물에 대한 해결책을 찾고 있었고 아래는 나를 위해 작동합니다. 참조 .

그리고 당신은 다음과 같이 함수를 호출합니다 :

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 번째 항목에 쉽게 액세스 할 수 없습니다.
Björn Lindqvist

6

또 다른 함수는 delimeter 함수로 문자열의 n 번째 부분을 얻습니다.

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

나는이 솔루션을 선택하여 구문 분석 된 테이블을 얻는 대신 단일 하위 문자열을 반환하는 옵션으로 선호합니다. 테이블 결과를 사용하면 그 용도가 있지만 필요한 것은 완벽하게 작동했습니다.
James H

5

이 시도:

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')

나는 그것을 겪었고 & 그것은 내가 원하는 것과 완벽하게 같습니다! 내가 선택한 특수 문자를 무시하도록 맞춤 설정할 수도 있습니다.
Vikas

5

다음 예는 재귀 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 데모


2


    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

2

함수 없이도 문자열을 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); 

1

나는 그것이 오래된 질문이라는 것을 알고 있지만, 어떤 사람은 내 솔루션에서 이익을 얻을 수 있다고 생각합니다.

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 FIDDLE

장점 :

  • 3 개의 하위 문자열 deliminator를 모두 ''로 구분합니다.
  • 성능을 저하 시키므로 while 루프를 사용하면 안됩니다.
  • 모든 결과 하위 문자열이 하나의 행에 표시되므로 피벗 할 필요가 없습니다.

한계 :

  • 하나는 전체 번호를 알아야합니다. 공백 (하위 문자열).

참고 : 솔루션은 하위 문자열을 최대 N까지 줄 수 있습니다.

한계를 극복하기 위해 다음과 같은 참조를 사용할 수 있습니다 .

그러나 다시 위의 솔루션 을 테이블에서 사용할 수 없습니다 (Actaully 나는 그것을 사용할 수 없었습니다).

다시 말하지만이 솔루션이 누군가를 도울 수 있기를 바랍니다.

업데이트 : 레코드가 50000보다 큰 경우 성능 이 저하되므로 사용 하지 않는 것이 좋습니다.LOOPS


1

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

1

거의 모든 다른 답변은 분할되는 문자열을 대체하여 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.

0

서버 통증 재귀 CTE 솔루션 테스트

MS SQL Server 2008 스키마 설정 :

create table Course( Courses varchar(100) );
insert into Course values ('Hello John Smith');

쿼리 1 :

with cte as
   ( select 
        left( Courses, charindex( ' ' , Courses) ) as a_l,
        cast( substring( Courses, 
                         charindex( ' ' , Courses) + 1 , 
                         len(Courses ) ) + ' ' 
              as varchar(100) )  as a_r,
        Courses as a,
        0 as n
     from Course t
    union all
      select 
        left(a_r, charindex( ' ' , a_r) ) as a_l,
        substring( a_r, charindex( ' ' , a_r) + 1 , len(a_R ) ) as a_r,
        cte.a,
        cte.n + 1 as n
    from Course t inner join cte 
         on t.Courses = cte.a and len( a_r ) > 0

   )
select a_l, n from cte
--where N = 1

결과 :

|    A_L | N |
|--------|---|
| Hello  | 0 |
|  John  | 1 |
| Smith  | 2 |

0

josejuan의 xml 기반 답변과 비슷하지만 xml 경로를 한 번만 처리하면 피벗이 약간 더 효율적이라는 것을 알았습니다.

select ID,
    [3] as PathProvidingID,
    [4] as PathProvider,
    [5] as ComponentProvidingID,
    [6] as ComponentProviding,
    [7] as InputRecievingID,
    [8] as InputRecieving,
    [9] as RowsPassed,
    [10] as InputRecieving2
    from
    (
    select id,message,d.* from sysssislog cross apply       ( 
          SELECT Item = y.i.value('(./text())[1]', 'varchar(200)'),
              row_number() over(order by y.i) as rn
          FROM 
          ( 
             SELECT x = CONVERT(XML, '<i>' + REPLACE(Message, ':', '</i><i>') + '</i>').query('.')
          ) AS a CROSS APPLY x.nodes('i') AS y(i)
       ) d
       WHERE event
       = 
       'OnPipelineRowsSent'
    ) as tokens 
    pivot 
    ( max(item) for [rn] in ([3],[4],[5],[6],[7],[8],[9],[10]) 
    ) as data

8:30에 달렸다

select id,
tokens.value('(/n[3])', 'varchar(100)')as PathProvidingID,
tokens.value('(/n[4])', 'varchar(100)') as PathProvider,
tokens.value('(/n[5])', 'varchar(100)') as ComponentProvidingID,
tokens.value('(/n[6])', 'varchar(100)') as ComponentProviding,
tokens.value('(/n[7])', 'varchar(100)') as InputRecievingID,
tokens.value('(/n[8])', 'varchar(100)') as InputRecieving,
tokens.value('(/n[9])', 'varchar(100)') as RowsPassed
 from
(
    select id, Convert(xml,'<n>'+Replace(message,'.','</n><n>')+'</n>') tokens
         from sysssislog 
       WHERE event
       = 
       'OnPipelineRowsSent'
    ) as data

9:20에 달렸다


0
CREATE FUNCTION [dbo].[fnSplitString] 
( 
    @string NVARCHAR(MAX), 
    @delimiter CHAR(1) 
) 
RETURNS @output TABLE(splitdata NVARCHAR(MAX) 
) 
BEGIN 
    DECLARE @start INT, @end INT 
    SELECT @start = 1, @end = CHARINDEX(@delimiter, @string) 
    WHILE @start < LEN(@string) + 1 BEGIN 
        IF @end = 0  
            SET @end = LEN(@string) + 1

        INSERT INTO @output (splitdata)  
        VALUES(SUBSTRING(@string, @start, @end - @start)) 
        SET @start = @end + 1 
        SET @end = CHARINDEX(@delimiter, @string, @start)

    END 
    RETURN 
END

그것을 사용하십시오

select *from dbo.fnSplitString('Querying SQL Server','')

0

누군가 분리 된 텍스트의 한 부분 만 얻으려면 이것을 사용할 수 있습니다.

fromSplitStringSep ( 'Word1 wordr2 word3', '')에서 *를 선택하십시오.

CREATE function [dbo].[SplitStringSep] 
(
    @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
  )

0

나는 이것을 바쳤다.

declare @x nvarchar(Max) = 'ali.veli.deli.';
declare @item nvarchar(Max);
declare @splitter char='.';

while CHARINDEX(@splitter,@x) != 0
begin
    set @item = LEFT(@x,CHARINDEX(@splitter,@x))
    set @x    = RIGHT(@x,len(@x)-len(@item) )
     select @item as item, @x as x;
end

주의해야 할 유일한 점은 '.'입니다. @x의 끝은 ​​항상 있어야합니다.


0

@NothingsI 불가능한 솔루션을 구축하거나 가장 많이 투표 된 답변에 대한 의견 (허용되는 답변 바로 아래)에 대해 다음과 같은 신속하고 더러운 솔루션이 내 자신의 요구를 충족시키는 것으로 나타났습니다 .

"첫 번째; 두 번째; 세 번째; 네 번째; 다섯 번째"라는 문자열이 주어지면 세 번째 토큰을 얻고 싶습니다. 이것은 우리가 문자열이 가질 토큰 수를 알고있는 경우에만 작동합니다.이 경우 5입니다. 그래서 내 행동 방식은 마지막 두 토큰을 잘라 내고 (내부 쿼리) 첫 두 토큰을 잘라내는 것입니다 ( 외부 쿼리)

나는 이것이 추악하다는 것을 알고 있으며 내가 있었던 특정 조건을 다루고 있지만 누군가가 유용하다고 생각하는 경우에 대비하여 게시하고 있습니다. 건배

select 
    REVERSE(
        SUBSTRING(
            reverse_substring, 
            0, 
            CHARINDEX(';', reverse_substring)
        )
    ) 
from 
(
    select 
        msg,
        SUBSTRING(
            REVERSE(msg), 
            CHARINDEX(
                ';', 
                REVERSE(msg), 
                CHARINDEX(
                    ';',
                    REVERSE(msg)
                )+1
            )+1,
            1000
        ) reverse_substring
    from 
    (
        select 'first;second;third;fourth;fifth' msg
    ) a
) b

이것은 우리가 문자열이 가질 토큰의 수를 아는 경우에만 작동합니다 -속보 제한 ...
Shnugo

0
declare @strng varchar(max)='hello john smith'
select (
    substring(
        @strng,
        charindex(' ', @strng) + 1,
        (
          (charindex(' ', @strng, charindex(' ', @strng) + 1))
          - charindex(' ',@strng)
        )
    ))

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.