【问题标题】:Table Normalization (Parse comma separated fields into individual records)表规范化(将逗号分隔的字段解析为单独的记录)
【发布时间】:2011-09-19 01:54:59
【问题描述】:

我有一张这样的桌子:

设备

DeviceId   Parts

1          Part1, Part2, Part3
2          Part2, Part3, Part4
3          Part1

我想创建一个表“零件”,将零件列中的数据导出到新表。之后我将删除 Parts 列

预期结果

零件

PartId PartName

  1      Part1
  2      Part2
  3      Part3
  4      Part4

设备部分

DeviceId PartId

  1      1
  1      2
  1      3
  2      2
  2      3
  2      4
  3      1

我可以在不使用游标的情况下在 SQL Server 2008 中执行此操作吗?

【问题讨论】:

  • 到目前为止你尝试了什么。在这里你需要的一个提示是一个带有 partID(Int, Identity(1,1)),partname 的表,并用 select distinct 插入其中。之后,一个 Join 将为你提供第二个表..
  • 到目前为止我已经尝试过游标,但我不喜欢这个解决方案,我觉得应该有更好的方法来做到这一点。

标签: sql sql-server tsql sql-server-2008 database-design


【解决方案1】:

-- 设置:

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')

--脚本:

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

-- 结果:

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   

【讨论】:

    【解决方案2】:

    您需要一个 Tally 表才能在没有光标的情况下完成此操作。

    按照说明在此处创建一个计数表:Tally Tables by Jeff Moden

    此脚本会将表放入您的 Temp 数据库,因此您可能需要更改“Use DB”语句

    然后您可以运行下面的脚本将设备和部件的细分插入到临时表中。然后,您应该能够通过部件名称加入您的部件表(以获取 ID)并插入到新的 DevicePart 表中。

    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) = ', '
    

    【讨论】:

      【解决方案3】:

      看看使用fn_Split 从逗号分隔值创建表变量。 然后,您可以使用它来驱动插入。

      编辑:实际上,我认为您可能仍然需要一个光标。留下这个答案以防 fn_Split 有帮助。

      【讨论】:

      • 老天,请不要使用那个功能。它使用 mTVF 和 WHILE 循环。它是可用的最慢的分离器之一。
      【解决方案4】:

      如果每个设备有最大零件数,是的,可以在没有光标的情况下完成,但这很复杂。

      基本上,为 PartID 字符串中的每个可能索引创建一个表(或视图或子查询),其中包含一个 DeviceID 和一个 PartID 列。这可以通过使用 fn_split 或您选择的其他方法使 PartID 列计算列来完成。从那里您对该表执行多个自联合,每个 PartID 列的自联合中都有一个表。 self-UNION 中的每个表只有一个 PartID 列包含在该表的查询的选择列表中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-02
        • 2012-01-28
        • 1970-01-01
        • 2015-02-01
        • 2021-12-13
        相关资源
        最近更新 更多