SQL Server:将值从具有多个值的列拆分为多行

时间:2018-08-23 00:45:07

标签: sql sql-server sql-server-2008

我有当前看起来像这样的数据(管道表示单独的列):

ID | Sex | Purchase           | Type  
 1 | M   | Apple, Apple       | Food, Food  
 2 | F   | Pear, Barbie, Soap | Food, Toys, Cleaning  

如您所见,PurchaseType列具有多个逗号分隔的值(这些列中的某些单元格实际上记录了多达50个以上的值)。我希望数据看起来像这样:

ID | Sex | Purchase | Type  
 1 | M   | Apple    | Food  
 1 | M   | Apple    | Food  
 2 | F   | Pear     | Food  
 2 | F   | Barbie   | Toys  
 2 | F   | Soap     | Cleaning

关于如何使用SQL执行此操作的任何想法?谢谢大家的帮助。

编辑:只是为了表明这与其他一些问题不同。此处的关键是,每个唯一行的数据包含在两个单独的列中,即ID为#1的“购买”中的第二个单词应与“类型”中的第二个单词链接。我看到的其他问题是多个值仅包含在一个列中。

2 个答案:

答案 0 :(得分:0)

基本上,您将需要定界分隔符功能。周围有很多。在这里,我使用的是Jeff Moden http://www.sqlservercentral.com/articles/Tally+Table/72993/DelimitedSplit8K

-- create the sample table
create table #sample
(
    ID  int,
    Sex char,
    Purchase    varchar(20),
    Type        varchar(20)
)

-- insert the sample data
insert into #sample (ID, Sex, Purchase, Type) select 1, 'M', 'Apple,Apple', 'Food,Food'
insert into #sample (ID, Sex, Purchase, Type) select 2, 'M', 'Pear,Barbie,Soap', 'Food,Toys,Cleaning'

select  s.ID, s.Sex, Purchase = p.Item, Type = t.Item
from    #sample s
        cross apply DelimitedSplit8K(Purchase, ',') p
        cross apply DelimitedSplit8K(Type, ',') t
where   p.ItemNumber    = t.ItemNumber

drop table #sample

答案 1 :(得分:0)

编辑:最初发布的问题的数据为字符串,管道字符为列定界符,且列内使用逗号。以下解决方案适用于此。

此后,对问题进行了编辑,以显示输入数据实际上在列中,而不是单个字符串。

我将解决方案留在这里,作为原始问题的有趣版本。


这是一个有趣的问题。我有一个适用于您的单行数据的解决方案。我从问题中不知道您是否要逐行处理它,但我想您会的。

如果是这样,它将起作用。我怀疑使用xml或不使用临时表可能是更好的方法,但是无论如何这是一种解决方案。

declare @row varchar(1000); set @row='2 | F | Pear, Barbie, Soap | Food, Toys, Cleaning'

declare @v table(i int identity, val varchar(1000), subval varchar(100))
insert @v select value as val, subval from STRING_SPLIT(@row,'|')
cross apply (select value as subval from STRING_SPLIT(value,',') s) subval

declare @v2 table(col_num int, subval varchar(100), correlation int)
insert @v2
select col_num, subval,
DENSE_RANK() over (partition by v.val order by i) as correlation
from @v v
join (
    select val, row_number()over (order by fst) as Col_Num 
    from (select val, min(i) as fst  from @v group by val) colnum
    ) c on c.val=v.val
order by i

select col1.subval as ID, col2.subval as Sex, col3.subval as Purchase, col4.subval as Type
from @v2 col1
join @v2 col2 on col2.col_num=2
join @v2 col3 on col3.col_num=3
join @v2 col4 on col4.col_num=4 and col4.correlation=col3.correlation
where col1.col_num=1

结果是:

ID  Sex Purchase    Type
2    F   Pear    Food
2    F   Barbie  Toys
2    F   Soap    Cleaning