2012-05-08 3 views
2

우리는 다음과 같은 테이블이 있다고 가정 결과 테이블 반환 :는 어떻게 열에서 문자열 값을 분할

id name member 
1 jacky a;b;c 
2 jason e 
3 kate i;j;k 
4 alex null 

가 지금은 다음 표를 반환하는 SQL 또는 T-SQL을 사용하려면를 :

1 jacky a 
1 jacky b 
1 jacky c 
2 jason e 
3 kate i 
...... 

어떻게 수행하나요? MSSQL, MYSQL 및 Oracle 데이터베이스를 사용하고 있습니다.

+0

Unpivot은 MSSQL 및 오라클에서 찾고있는 명령입니다. – xQbert

+0

@xQbert - 생각하지 않습니다. unpivot은 기능을 분할했지만, 내가 잘못 될 수 있습니다 ... –

답변

3

이 고안 한 수와 빠른도 될 수 최단판독 문자열 투 로우 스플리터이다.

함수 대신 순수 CTE를 사용하는 경우를 예로 들어 보겠습니다.

함수를 통한 로우 생성기 (루프 또는 CTE를 사용하여 구현 될 수 있음)는 여전히 가로 조인을 사용해야합니다 (DB2 및 Sybase의 경우 기능, LATERAL 키워드 사용; SQL Server에서 이것은 CROSS APPLY 및 OUTER APPLY와 유사 함) 함수에 의해 생성 된 분할 된 행을 주 테이블에 조인합니다.

순수 CTE 접근법은 함수 접근보다 빠를 수 있습니다. 속도 측정이 참 빠른 경우 단지 다른 솔루션에 비해 이것의 실행 계획을 확인하지만 프로파일에있다 :

with Pieces(theId, pn, start, stop) AS 
(
     SELECT id, 1, 1, charindex(';', member) 
     from tbl 

     UNION ALL 

     SELECT id, pn + 1, stop + 1, charindex(';', member, stop + 1) 
     from tbl 
     join pieces on pieces.theId = tbl.id 
     WHERE stop > 0 
) 
select 

     t.id, t.name, 

     word = 
     substring(t.member, p.start,    
      case WHEN stop > 0 THEN p.stop - p.start 
      ELSE 512 
      END) 

from tbl t 
join pieces p on p.theId = t.id 
order by t.id, p.pn 

출력 :

ID NAME WORD 
1 jacky a 
1 jacky b 
1 jacky c 
2 jason e 
3 kate i 
3 kate j 
3 kate k 
4 alex (null) 

자료 논리가 여기 소스 : T-SQL: Opposite to string concatenation - how to split string into multiple records

라이브 테스트 : http://www.sqlfiddle.com/#!3/2355d/1

2

음 ... Numbers 테이블에 대해 가르쳐 주신 Adam Machanic에게 먼저 소개시켜 드리겠습니다. 그는 또한이 Numbers 테이블을 사용하여 매우 빠른 스플릿 함수를 작성했습니다. 테이블을 반환하는 분할 기능을 구현 한 후

http://sqlblog.com/blogs/adam_machanic/archive/2006/07/12/splitting-a-string-of-unlimited-length.aspx

, 당신은 다음에 가입하고 원하는 결과를 얻을 수 있습니다.

+0

dbo.SplitString ('something, something, etc, etc, etc ...', ',') 함수를 이해합니다. 그러나이 함수로 결과 테이블을 얻는 방법. – DerekY

+0

@ user838204 기능을 사용하는 경우 CROSS APPLY 또는 OUTER APPLY를 사용해야합니다. 이 형식은 다음과 같습니다 :'SELECT * FROM tbl OUTER APPLY (select * FROM dbo.splitter (tbl.member))' –

1
IF OBJECT_ID('dbo.Users') IS NOT NULL 
    DROP TABLE dbo.Users; 

CREATE TABLE dbo.Users 
(
    id INT IDENTITY NOT NULL PRIMARY KEY, 
    name VARCHAR(50) NOT NULL, 
    member VARCHAR(1000) 
) 
GO 

INSERT INTO dbo.Users(name, member) VALUES 
    ('jacky', 'a;b;c'), 
    ('jason', 'e'), 
    ('kate', 'i;j;k'), 
    ('alex', NULL); 
GO 

DECLARE @spliter CHAR(1) = ';'; 
WITH Base AS 
(
    SELECT 1 AS n 
    UNION ALL 
    SELECT n + 1 
    FROM Base 
    WHERE n < CEILING(SQRT(1000)) --generate numbers from 1 to 1000, you may change it to a larger value depending on the member column's length. 
) 
, Nums AS --Numbers Common Table Expression, if your database version doesn't support it, just create a physical table. 
(
    SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 0)) AS n 
    FROM Base AS B1 CROSS JOIN Base AS B2 
) 
SELECT id, 
     SUBSTRING(member, n, CHARINDEX(@spliter, member + @spliter, n) - n) AS element 
FROM dbo.Users 
    JOIN Nums 
    ON n <= DATALENGTH(member) + 1 
    AND SUBSTRING(@spliter + member, n, 1) = @spliter 
ORDER BY id 
OPTION (MAXRECURSION 0); --Nums CTE is generated recursively, we don't want to limit recursion count.