我有一个旧的复古系统,桌子看起来像这样。
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的视图。
它将用于与包含答案的表的连接,以便进行临时统计查询。
有没有一种好方法可以在不使用游标等的情况下执行此操作?
答案 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