【问题标题】:Transform hierarchical data into flat table将分层数据转换为平面表
【发布时间】:2016-12-27 11:06:54
【问题描述】:

我正在使用 ms sql 研究分层数据(作为概括工单的解决方案)。

*

我愿意对我的初始表进行​​设计更改和/或添加其他 表格。

*

这是我的数据

ID  ParentID    Type        Value
38  0           Num         327
39  38          Sector      21
40  38          Sector      22
43  40          Product     NS
44  40          Product     MS
50  40          Temp        RAS
48  44          Quantity    60
47  43          Quantity    25
41  39          Product     ARF
42  39          Product     BRF
49  39          Temp        RAS
51  39          Cible       Acarien A.
46  42          Quantity    30
52  42          Cible       Acarien B.
45  41          Quantity    20

我想把它变成:

Num Sector  Product Quantity
327 21      ARF     20
327 21      BRF     30
327 22      NS      25
327 22      MS      60

[使用 Gurwinder 回答的结果]

num sector  product    quantity
327 22      MS         60
327 22      NS         25
327 21      BRF        30
327 21      BRF        Acarien B.
327 21      ARF        20

[顺吾的做法]

<root>
  <row Num="327" Sector="s2" Temp="normal" />
  <row Num="327" Sector="s2" Product="BRF" Qte="70" />
  <row Num="327" Sector="s2" Product="ARF" Qte="45" />
  <row Num="327" Sector="s1" Temp="normal" />
  <row Num="327" Sector="s1" Cible="Acarien a." />
  <row Num="327" Sector="s1" Product="NS" Qte="35" />
  <row Num="327" Sector="s1" Product="NS" Cible="Acarien b." />
  <row Num="327" Sector="s1" Product="MS" Qte="60" />
</root>

非常感谢你们抽出时间。

【问题讨论】:

  • 第二个例子的输出是什么?
  • 你试过我的答案了吗?我刚刚做到了,您的第二个示例完全按照您发布它的方式返回......您的问题是两个折叠:1)动态命名的列和2)层次结构。这两个例子都是直截了当的三个层次。这是修复吗?
  • 正在使用您的模型对其进行测试。
  • 非常感谢,你达到了目标先生[动态命名列和层次结构]问题是层次结构的级别不固定(但在99%的情况下3)
  • Ismail,您发布的结果与您发布的数据不兼容。对我来说,如果没有一个真实的例子,你的层次结构是如何工作的。

标签: sql sql-server performance hierarchical-data


【解决方案1】:

这个技巧怎么样?

DECLARE @tbl TABLE(ID INT,ParentID INT,Type VARCHAR(10),Value VARCHAR(10))
INSERT INTO @tbl VALUES
 (1,0,'Num','327')
,(2,1,'Sector','21')
,(3,1,'Sector','22')
,(4,2,'Product','ARF')
,(5,2,'Product','BRF')
,(6,3,'Product','NS')
,(7,3,'Product','MS')
,(8,4,'Quantity','20')
,(9,5,'Quantity','30')
,(10,6,'Quantity','25')
,(11,7,'Quantity','60');

WITH recCTE AS
(
    SELECT *,0 AS HLevel,Type + N'="' + CAST(Value AS NVARCHAR(MAX)) + N'" ' AS attr
    FROM @tbl WHERE ParentID=0

    UNION ALL

    SELECT t.*,r.HLevel+1,attr+t.Type + N'="' + CAST(t.Value AS NVARCHAR(MAX)) + N'" '
    FROM @tbl AS t
    INNER JOIN recCTE AS r ON t.ParentID=r.ID
)
SELECT CAST(N'<row ' + attr  + N'/>' AS XML)
FROM recCTE
WHERE HLevel=3
FOR XML PATH(''),ROOT('root')

结果

<root>
  <row Num="327" Sector="22" Product="MS" Quantity="60" />
  <row Num="327" Sector="22" Product="NS" Quantity="25" />
  <row Num="327" Sector="21" Product="BRF" Quantity="30" />
  <row Num="327" Sector="21" Product="ARF" Quantity="20" />
</root>

这个 XML 很容易查询...最深层次(这里我取 HLevel=3)一般可以找到 - 但您需要提供更多详细信息...

更新

以下将不使用给定深度作为过滤器,而是使用查询来检查节点是否为叶节点

我在最后加了一行

DECLARE @tbl TABLE(ID INT,ParentID INT,Type VARCHAR(100),Value VARCHAR(100))
INSERT INTO @tbl VALUES
 (1,0,'Num','327')
,(2,1,'Sector','21')
,(3,1,'Sector','22')
,(4,2,'Product','ARF')
,(5,2,'Product','BRF')
,(6,3,'Product','NS')
,(7,3,'Product','MS')
,(8,4,'Quantity','20')
,(9,5,'Quantity','30')
,(10,6,'Quantity','25')
,(11,7,'Quantity','60')
,(13,11,'SomeMore','Test as fourth');

WITH recCTE AS
(
    SELECT t.*
          ,0 AS HLevel
          ,t.Type + N'="' + CAST(t.Value AS NVARCHAR(MAX)) + N'" ' AS attr
          ,CASE WHEN EXISTS(SELECT 1 FROM @tbl AS x WHERE x.ParentID=t.ID) THEN 0 ELSE 1 END AS IsLeaf
    FROM @tbl AS t WHERE ParentID=0

    UNION ALL

    SELECT t.*
          ,r.HLevel+1
          ,attr+t.Type + N'="' + CAST(t.Value AS NVARCHAR(MAX)) + N'" '
          ,CASE WHEN EXISTS(SELECT 1 FROM @tbl AS x WHERE x.ParentID=t.ID) THEN 0 ELSE 1 END AS IsLeaf
    FROM @tbl AS t
    INNER JOIN recCTE AS r ON t.ParentID=r.ID
)
SELECT CAST(N'<row ' + attr  + N'/>' AS XML)
FROM recCTE
WHERE IsLeaf=1
FOR XML PATH(''),ROOT('root')

结果

<root>
  <row Num="327" Sector="22" Product="MS" Quantity="60" SomeMore="Test as fourth" />
  <row Num="327" Sector="22" Product="NS" Quantity="25" />
  <row Num="327" Sector="21" Product="BRF" Quantity="30" />
  <row Num="327" Sector="21" Product="ARF" Quantity="20" />
</root>

更新 2:使用您的真实数据

正如您已经发现的那样,您的问题非常混乱......不知道您真正需要什么,但如果我通过此查询运行您的真实数据,我会得到:

DECLARE @tbl TABLE(ID INT,ParentID INT,Type VARCHAR(100),Value VARCHAR(100))
INSERT INTO @tbl VALUES
 (38,0,'Num','327')
,(39,38,'Sector','21')
,(40,38,'Sector','22')
,(43,40,'Product','NS')
,(44,40,'Product','MS')
,(50,40,'Temp','RAS')
,(48,44,'Quantity','60')
,(47,43,'Quantity','25')
,(41,39,'Product','ARF')
,(42,39,'Product','BRF')
,(49,39,'Temp','RAS')
,(51,39,'Cible','Acarien A.')
,(46,42,'Quantity','30')
,(52,42,'Cible','Acarien B.')
,(45,41,'Quantity','20');

WITH recCTE AS
(
    SELECT t.*
          ,0 AS HLevel
          ,t.Type + N'="' + CAST(t.Value AS NVARCHAR(MAX)) + N'" ' AS attr
          ,CASE WHEN EXISTS(SELECT 1 FROM @tbl AS x WHERE x.ParentID=t.ID) THEN 0 ELSE 1 END AS IsLeaf
    FROM @tbl AS t WHERE ParentID=0

    UNION ALL

    SELECT t.*
          ,r.HLevel+1
          ,attr+t.Type + N'="' + CAST(t.Value AS NVARCHAR(MAX)) + N'" '
          ,CASE WHEN EXISTS(SELECT 1 FROM @tbl AS x WHERE x.ParentID=t.ID) THEN 0 ELSE 1 END AS IsLeaf
    FROM @tbl AS t
    INNER JOIN recCTE AS r ON t.ParentID=r.ID
)
SELECT CAST(N'<row ' + attr  + N'/>' AS XML)
FROM recCTE
WHERE IsLeaf=1
FOR XML PATH(''),ROOT('root')

结果

<root>
  <row Num="327" Sector="22" Temp="RAS" />
  <row Num="327" Sector="22" Product="MS" Quantity="60" />
  <row Num="327" Sector="22" Product="NS" Quantity="25" />
  <row Num="327" Sector="21" Temp="RAS" />
  <row Num="327" Sector="21" Cible="Acarien A." />
  <row Num="327" Sector="21" Product="BRF" Quantity="30" />
  <row Num="327" Sector="21" Product="BRF" Cible="Acarien B." />
  <row Num="327" Sector="21" Product="ARF" Quantity="20" />
</root>

【讨论】:

  • 非常感谢您为我提供了很大的帮助,甚至比我预期的还要好。
  • 我正处于使用这种分层表设计进行测试的阶段,这就是为什么问题很混乱,请你指导我更好地设计我需要的东西[工单的泛化]
  • @IsmailKarchi 请用指向此的链接开始一个新问题,并在我的答案下方放置一个链接以提醒我。更好的设计是 - 很可能,因为 Key-Value-Pairsself-referenced-hierarchy 的连接似乎过于复杂......但我不足够了解您的需求。开始一个新问题,详细了解您的实际情况(行数、用例、组数、数据完整性......以及 - 主要问题! - 为什么?)
【解决方案2】:
select t1.value num,
    t2.value sector,
    t3.value product,
    t4.value quantity
from table t1
inner join table t2
on t1.id = t2.parentid
and t1.parentid = 0
inner join table t3
on t2.id = t3.parentid
inner join table t4
on t3.id = t4.parentid;

【讨论】:

  • 谢谢,它只解决了这个特定的情况,如果我有多个值怎么办。举个例子吧
  • 请在问题中发布
猜你喜欢
  • 2010-12-16
  • 2022-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多