给出一张表:
|Name | Hobbies |
-----------------------------------
|Joe | Eating,Running,Golf |
|Dafydd | Swimming,Coding,Gaming |
我想将这些行拆分为:
|Name | Hobby |
----------------------
|Joe | Eating |
|Joe | Running |
|Joe | Golf |
|Dafydd | Swimming |
|Dafydd | Coding |
|Dafydd | Gaming |
我已经在下面完成了这个(示例已准备好在SSMS中运行),购买我的解决方案使用我觉得很难看的游标。有没有更好的方法呢?我在SQL Server 2008 R2上,如果有任何新的东西可以帮助我。
由于
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Split]') and xtype in (N'FN', N'IF', N'TF')) drop function [dbo].Split
go
CREATE FUNCTION dbo.Split (@sep char(1), @s varchar(512))
RETURNS table
AS
RETURN (
WITH Pieces(pn, start, stop) AS (
SELECT 1, 1, CHARINDEX(@sep, @s)
UNION ALL
SELECT pn + 1, stop + 1, CHARINDEX(@sep, @s, stop + 1)
FROM Pieces
WHERE stop > 0
)
SELECT pn,
SUBSTRING(@s, start, CASE WHEN stop > 0 THEN stop-start ELSE 512 END) AS s
FROM Pieces
)
go
declare @inputtable table (
name varchar(200) not null,
hobbies varchar(200) not null
)
declare @outputtable table (
name varchar(200) not null,
hobby varchar(200) not null
)
insert into @inputtable values('Joe', 'Eating,Running,Golf')
insert into @inputtable values('Dafydd', 'Swimming,Coding,Gaming')
select * from @inputtable
declare inputcursor cursor for
select name, hobbies
from @inputtable
open inputcursor
declare @name varchar(255), @hobbiescsv varchar(255)
fetch next from inputcursor into @name, @hobbiescsv
while(@@FETCH_STATUS <> -1) begin
insert into @outputtable
select @name, splithobbies.s
from dbo.split(',', @hobbiescsv) splithobbies
fetch next from inputcursor into @name, @hobbiescsv
end
close inputcursor
deallocate inputcursor
select * from @outputtable
答案 0 :(得分:9)
使用字符串解析函数,如找到的here。关键是使用CROSS APPLY为基表中的每一行执行函数。
CREATE FUNCTION [dbo].[fnParseStringTSQL] (@string NVARCHAR(MAX),@separator NCHAR(1))
RETURNS @parsedString TABLE (string NVARCHAR(MAX))
AS
BEGIN
DECLARE @position int
SET @position = 1
SET @string = @string + @separator
WHILE charindex(@separator,@string,@position) <> 0
BEGIN
INSERT into @parsedString
SELECT substring(@string, @position, charindex(@separator,@string,@position) - @position)
SET @position = charindex(@separator,@string,@position) + 1
END
RETURN
END
go
declare @MyTable table (
Name char(10),
Hobbies varchar(100)
)
insert into @MyTable
(Name, Hobbies)
select 'Joe', 'Eating,Running,Golf'
union all
select 'Dafydd', 'Swimming,Coding,Gaming'
select t.Name, p.String
from @mytable t
cross apply dbo.fnParseStringTSQL(t.Hobbies, ',') p
DROP FUNCTION [dbo].[fnParseStringTSQL]
答案 1 :(得分:4)
请执行以下操作:
select *
from @inputtable
outer apply dbo.split(',', hobbies) splithobbies
答案 2 :(得分:3)
在您的数据库中创建此功能:
CREATE FUNCTION dbo.Split(@origString varchar(max), @Delimiter char(1))
returns @temptable TABLE (items varchar(max))
as
begin
declare @idx int
declare @split varchar(max)
select @idx = 1
if len(@origString )<1 or @origString is null return
while @idx!= 0
begin
set @idx = charindex(@Delimiter,@origString)
if @idx!=0
set @split= left(@origString,@idx - 1)
else
set @split= @origString
if(len(@split)>0)
insert into @temptable(Items) values(@split)
set @origString= right(@origString,len(@origString) - @idx)
if len(@origString) = 0 break
end
return
end
然后只需在Select语句中调用它,并使用cross apply连接到函数
Select t.Name,
s.items as 'Hobby'
from dbo.MyTable as t
Cross Apply dbo.Split(t.Hobbies,',') as s
答案 3 :(得分:0)
我通常更喜欢使用XML
将CSV列表拆分为表值格式。你可以检查这个功能:
CREATE FUNCTION dbo.SplitStrings_XML
(
@List NVARCHAR(MAX),
@Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
SELECT Item = y.i.value('(./text())[1]', 'nvarchar(4000)')
FROM
(
SELECT x = CONVERT(XML, '<i>'
+ REPLACE(@List, @Delimiter, '</i><i>')
+ '</i>').query('.')
) AS a CROSS APPLY x.nodes('i') AS y(i)
);
GO
以及以下article了解更多显示如何执行此操作的技巧。然后,您只需使用CROSS APPLY
子句来应用该函数。