2017-08-08 144 views
0

SQL很新,但我需要一些帮助,我相信这是一个简单的修复。SQL Sting拆分为单列

我在名为'Produce'的表内有一列数据,其中水果的类型存储在名为'Fruit'的列中。此列中的某些值由逗号分隔。

有没有一种简单的方法来分割下面的结果,使结果成为单列唯一条目?

E.g.示例表

Fruit 
----- 
Apple 
Plum 
Pear, Mango 
Pear 

什么我希望能回报是以下:

Fruit 
----- 
Apple 
Plum 
Pear 
Mango 

我曾尝试使用字符串分割功能,但我想我有它彻底。任何人都可以帮助提供一些关于如何做到这一点的解释吗?如果有帮助,我正在使用T-SQL。

在此先感谢。

+0

T-SQL在SQL SERVER?什么版本? – xQbert

+1

[将逗号分隔的字符串变成单个行]可能的重复(https://stackoverflow.com/questions/5493510/turning-a-comma-separated-string-into-individual-rows) – xQbert

回答

0

要解决的核心问题是停止将值存储为以逗号分隔的列表。保持数据正常化。有了这样说......每个人都需要一个良好的分离器...

declare @table table (Fruit varchar(64)) 
insert into @table 
values 
('Apple'), 
('Plum'), 
('Pear,Mango'), 
('Pear') 

select distinct 
    Item 
from 
    @table 
cross apply 
    dbo.DelimitedSplit8K(Fruit,',') 

或者,如果你的SQL Server 2016上...

select distinct 
    Item 
from 
    @table 
cross apply 
    string_split(Fruit,',') 

中的作用

SET ANSI_NULLS ON 
GO 

SET QUOTED_IDENTIFIER ON 
GO 

CREATE FUNCTION [dbo].[DelimitedSplit8K] (@pString VARCHAR(8000), @pDelimiter CHAR(1)) 
--WARNING!!! DO NOT USE MAX DATA-TYPES HERE! IT WILL KILL PERFORMANCE! 

RETURNS TABLE WITH SCHEMABINDING AS 
RETURN 

/* "Inline" CTE Driven "Tally Table" produces values from 1 up to 10,000... 
enough to cover VARCHAR(8000)*/ 

    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 
       ),       --10E+1 or 10 rows 
     E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows 
     E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max 
cteTally(N) AS (--==== This provides the "base" CTE and limits the number of rows right up front 
        -- for both a performance gain and prevention of accidental "overruns" 
       SELECT TOP (ISNULL(DATALENGTH(@pString),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4 
       ), 
cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter) 
       SELECT 1 UNION ALL 
       SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(@pString,t.N,1) = @pDelimiter 
       ), 
cteLen(N1,L1) AS(--==== Return start and length (for use in substring) 
       SELECT s.N1, 
         ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,s.N1),0)-s.N1,8000) 
        FROM cteStart s 
       ) 
--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found. 
SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1), 
     Item  = SUBSTRING(@pString, l.N1, l.L1) 
    FROM cteLen l 
; 
GO 

Jeff Moden Article for Function

0

这可以用纯SQL来完成,不需要用户编写的函数。

SQL服务器

WITH 
    fruittable 
    AS 
     ( SELECT 'Apple' fruit, 1 id 
     UNION ALL 
      SELECT 'Banana,Apple', 2 
     UNION ALL 
      SELECT 'Tomato,Grapefruit,Apple', 3 
     UNION ALL 
      SELECT 'Watermelon,Persimmons', 4 
     ), 
    split (fruit, id, leftover) 
    AS 
     (SELECT case when len(fruit) = 0 or fruit is null then null else left(fruit + ',', charindex(',',fruit + ',') -1) end AS fruit 
       , id 
       , case when len(fruit) = 0 or fruit is null then null else right(fruit + ',', len(fruit) - charindex(',',fruit + ',') + 1) end as leftover 
      FROM fruittable 
     UNION ALL 
     SELECT case when len(leftover) = 0 or leftover is null then null else left(leftover, charindex(',',leftover) - 1) end AS fruit 
       , id 
       , case when len(leftover) = 0 or leftover is null then null else substring(leftover, charindex(',',leftover) + 1, len(leftover)) end as leftover 
      FROM split 
      WHERE fruit IS NOT NULL) 
SELECT fruit, id 
    FROM split where fruit is not null 
    order by fruit, id; 

甲骨文

WITH 
    fruittable 
    AS 
     (SELECT 'Apple' fruit, 1 id 
      FROM DUAL 
     UNION ALL 
     SELECT 'Banana,Apple', 2 
      FROM DUAL 
     UNION ALL 
     SELECT 'Tomato,Grapefruit,Apple', 3 
      FROM DUAL 
     UNION ALL 
     SELECT 'Watermelon,Persimmons', 4 
      FROM DUAL), 
    split (fruit, id, leftover) 
    AS 
     (SELECT SUBSTR (fruit || ',', 1, INSTR (fruit || ',', ',') - 1) AS fruit 
       , id 
       , SUBSTR (fruit || ',', INSTR (fruit || ',', ',') + 1) AS leftover 
      FROM fruittable 
     UNION ALL 
     SELECT SUBSTR (leftover, 1, INSTR (leftover, ',') - 1) AS fruit 
       , id 
       , SUBSTR (leftover, INSTR (leftover, ',') + 1) AS leftover 
      FROM split 
      WHERE fruit IS NOT NULL) 
    SELECT fruit, id 
    FROM split 
    WHERE fruit IS NOT NULL 
ORDER BY fruit, id