将字符串转换为行

时间:2015-07-02 10:48:01

标签: sql-server tsql

我有一个旧的复古系统,桌子看起来像这样。

OptionsTable
id   options
===  ========================
101  Apple,Banana            
102  Audi,Mercedes,Volkswagen

在使用数据的应用程序中,函数会将options列分解为可管理列表并填充下拉列表等。

问题是这种数据不具有SQL友好性,因此难以进行临时查询和报告。

为此,我想将数据转换为更友好的视图,如下所示:

OptionsView
id   name        value
===  ==========  =====
101  Apple           1
101  Banana          2
102  Audi            1
102  Mercedes        2
102  Volkswagen      3

现在,有一些关于在t-sql中将字符串拆分成行的主题(Turning a Comma Separated string into individual rows会想到),但除了将字符串拆分成行之外,我还需要根据位置生成值字符串。

计划是制作隐藏原始表的uglines的视图。

它将用于与包含答案的表的连接,以便进行临时统计查询。

有没有一种好方法可以在不使用游标等的情况下执行此操作?

3 个答案:

答案 0 :(得分:0)

也许添加一个udf对你的需求来说太过分了,但我很久以前创建了一个split函数,它返回值,字符串中的起始位置和索引。有了它,这种情况下的用法将是:

select id, String as [Name], ItemIndex as value from OptionsTable
outer apply dbo.Split(options, ',')

结果:

id  Name    value
101 Apple   1
101 Banana  2
102 Audi    1
102 Mercedes    2
102 Volkswagen  3

分裂函数(从那时起未经修改):

ALTER function [dbo].[Split] ( 
@StringToSplit varchar(2048),
@Separator varchar(128))
returns table as return

with indices as
( 
select 0 S, 1 E, 0 I
union all
select E, charindex(@Separator, @StringToSplit, E) + len(@Separator) , I + 1
from indices
where E > S 
)
select substring(@StringToSplit,S, 
case when E > len(@Separator) then e-s-len(@Separator) else len(@StringToSplit) - s + 1 end) String
,S StartIndex, I ItemIndex        
from indices where S >0

答案 1 :(得分:0)

这应该适合你:

DECLARE @OptionsTable TABLE
(
    id INT
    , options VARCHAR(100)
);

INSERT INTO @OptionsTable (id, options)
VALUES (101, 'Apple,Banana')
    , (102, 'Audi,Mercedes,Volkswagen');

SELECT OT.id, T.name, t.value
FROM @OptionsTable AS OT
CROSS APPLY (
    SELECT T.column1, ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
    FROM dbo.GetTableFromList(OT.options, ',') AS T
    ) AS T(name, value);

这里dbo.GetTableFromList是一个分裂字符串函数 CROSS APPLY为每一行执行此函数,导致选项在单独的行中拆分为名称。我使用ROW_NUMBER()添加值行,如果您想按名称排序结果集,请使用ROW_NUMBER() OVER (ORDER BY t.column1),这应该并且可能会使结果始终保持一致。

<强>结果:

id  name    value
-----------------
101 Apple       1
101 Banana      2
102 Audi        1
102 Mercedes    2
102 Volkswagen  3

答案 2 :(得分:0)

您可以将字符串转换为XML,然后解析字符串以将其转置为如下所示的行:

SELECT A.[id]
      ,Split.a.value('.', 'VARCHAR(100)') AS Name
      ,ROW_NUMBER() OVER (PARTITION BY [id] ORDER BY (SELECT NULL)) as Value 
FROM (
    SELECT [id]
        ,CAST('<M>' + REPLACE([options], ',', '</M><M>') + '</M>' AS XML) AS Name
    FROM optionstable
    ) AS A
CROSS APPLY Name.nodes('/M') AS Split(a);

致谢:@SRIRAM

SQL Fiddle Demo