Table Normalization (Parse comma separated fields into individual records)
我有一张这样的桌子:
设备
1 2 3 4 5 | DeviceId Parts 1 Part1, Part2, Part3 2 Part2, Part3, Part4 3 Part1 |
我想创建一个表 \\'Parts\\',将 Parts 列中的数据导出到新表。之后我将删除 Parts 列
预期结果
零件
1 2 3 4 5 6 | PartId PartName 1 Part1 2 Part2 3 Part3 4 Part4 |
设备部件
1 2 3 4 5 6 7 8 9 | DeviceId PartId 1 1 1 2 1 3 2 2 2 3 2 4 3 1 |
我可以在 SQL Server 2008 中不使用游标来执行此操作吗?
-- 设置:
1 2 3 4 5 6 7 8 9 | DECLARE @Device TABLE(DeviceId INT PRIMARY KEY, Parts VARCHAR(1000)) DECLARE @Part TABLE(PartId INT IDENTITY(1,1) PRIMARY KEY, PartName VARCHAR(100)) DECLARE @DevicePart TABLE(DeviceId INT, PartId INT) INSERT @Device VALUES (1, 'Part1, Part2, Part3'), (2, 'Part2, Part3, Part4'), (3, 'Part1') |
--脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | DECLARE @DevicePartTemp TABLE(DeviceId INT, PartName VARCHAR(100)) INSERT @DevicePartTemp SELECT DeviceId, ltrim(x.value('.', 'varchar(100)')) FROM ( SELECT DeviceId, CAST('<x>' + REPLACE(Parts, ',', '</x><x>') + '</x>' AS xml) XmlColumn FROM @Device )tt CROSS apply XmlColumn.nodes('x') AS Nodes(x) INSERT @Part SELECT DISTINCT PartName FROM @DevicePartTemp INSERT @DevicePart SELECT tmp.DeviceId, prt.PartId FROM @DevicePartTemp tmp JOIN @Part prt ON prt.PartName = tmp.PartName |
-- 结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | SELECT * FROM @Part PartId PartName ----------- --------- 1 Part1 2 Part2 3 Part3 4 Part4 SELECT * FROM @DevicePart DeviceId PartId ----------- ----------- 1 1 1 2 1 3 2 2 2 3 2 4 3 1 |
您将需要一个 Tally 表来完成此操作,而无需使用光标。
按照说明在此处创建计数表:Jeff Moden 的计数表
此脚本会将表放入您的 Temp 数据库,因此您可能想要更改 "Use DB" 语句
然后您可以运行下面的脚本将设备和部件的细分插入到临时表中。然后,您应该能够通过部件名称加入您的部件表(以获取 ID)并插入到新的 DevicePart 表中。
1 2 3 4 5 6 7 8 | SELECT *, --substring(d.parts, 1, t.n) SUBSTRING(d.parts, t.n, charindex(', ', d.parts + ', ',t.n) - t.n) 'Part' INTO #devicesparts FROM device d CROSS JOIN tally t WHERE t.n < (SELECT MAX(len(parts))+ 1 FROM device) AND SUBSTRING(', ' + d.parts, t.n, 1) = ', ' |
如果每个设备有最大零件数,是的,可以在没有光标的情况下完成,但这很复杂。
基本上,为 PartID 字符串中的每个可能索引创建一个表(或视图或子查询),其中包含一个 DeviceID 和一个 PartID 列。这可以通过使用 fn_split 或您选择的其他方法使 PartID 列计算列来完成。从那里您对该表执行多个自联合,每个 PartID 列的自联合中都有一个表。 self-UNION 中的每个表只有一个 PartID 列包含在该表的查询的选择列表中。
看看使用 fn_Split 从逗号分隔值创建表变量。
然后,您可以使用它来驱动插入。
编辑:实际上,我认为您可能仍然需要一个光标。留下这个答案以防 fn_Split 有帮助。