如何将 RELATIONAL 数据分解为 HIERARCHY 数据结构?

Whi*_*row 1 sql-server-2008 sql-server hierarchy

我有一个返回以下数据集的查询:

RELATIONid MAPid  D1id   D2id  D3id
4999       4999   626    1250    7 
5000       5000   626    1250    8
Run Code Online (Sandbox Code Playgroud)

对于下一步,我需要将这些数据集绑定到树视图(层次结构)中。我需要将此数据集转换为以下内容:

Nodeid   ParentNodeid  Header
626       null           D1
1250      626            D2
7         1250           D3
8         1250           D3 
Run Code Online (Sandbox Code Playgroud)

我如何从原始数据集中实现这些结构?


我还有一个问题要问,数据结构比前一个复杂(一点点)。假设我有这样的示例数据集:

RELATIONid MAPid  D1id   D2id  D3id
4999       4999   626    1250    7 
5000       5000   626    1250    8
5001       5001   627    1300    10 
5002       5002   627    1300    12 
5003       5003   628    1400    15 
Run Code Online (Sandbox Code Playgroud)

从以下数据集中,我们有 3 个 MainParent:626, 627, 628并且转换(交叉应用)输出期望将是这样的:

Nodeid   ParentNodeid  Header
626       null           D1
1250      626            D2
7         1250           D3
8         1250           D3
627       null           D1
1300      627            D2
10        1300           D3
12        1300           D3
628       null           D1
1400      628            D2
15        1400           D3
Run Code Online (Sandbox Code Playgroud)

请注意,数据按顺序排列,ParentNode然后是其节点数据。

And*_*y M 6

交叉申请似乎非常适合这项工作:

SELECT
  v.Nodeid,
  v.ParentNodeid,
  v.Header
FROM
  dbo.atable
  CROSS APPLY
  (
    VALUES
    (D1id, NULL, 'D1'),
    (D2id, D1id, 'D2'),
    (D3id, D2id, 'D3')
  ) AS v (Nodeid, ParentNodeid, Header)
;
Run Code Online (Sandbox Code Playgroud)

对于源数据集的每一行,CROSS APPLY 使用 VALUES 行构造函数生成三个,明确指定原始集合的哪一列进入哪个新列。

现在,如果源中的某些对重复,则上述内容将返回重复项。您可以使用 DISTINCT 来抑制它们:

SELECT DISTINCT
  v.Nodeid,
  v.ParentNodeid,
  v.Header
...
Run Code Online (Sandbox Code Playgroud)

为了使转换集遵循 的顺序D1id ASC, D2id ASC, D3id ASC,您可以在输出中包含这些列并使用它们进行排序:

SELECT DISTINCT
  t.D1id,
  t.D2id,
  t.D3id,
  v.Nodeid,
  v.ParentNodeid,
  v.Header
FROM
  dbo.atable AS t
  CROSS APPLY
  (
    VALUES
    (t.D1id, NULL  , 'D1'),
    (t.D2id, t.D1id, 'D2'),
    (t.D3id, t.D2id, 'D3')
  ) AS v (Nodeid, ParentNodeid, Header)
ORDER BY
  t.D1id ASC,
  t.D2id ASC,
  t.D3id ASC
;
Run Code Online (Sandbox Code Playgroud)

您必须将它们包含在 SELECT 中的原因是,当您有 DISTINCT 时,您只能按 SELECT 子句中的列进行排序。自然地,结果集也将包括三个额外的列。如果您不希望它们出现在输出中,您可以使用上面的作为派生表:您的外部 SELECT 将仅提取三个必需的列并按其他三个列排序:

SELECT
  Nodeid,
  ParentNodeid,
  Header
FROM
(
  SELECT DISTINCT
    t.D1id,
    t.D2id,
    t.D3id,
    v.Nodeid,
    v.ParentNodeid,
    v.Header
  FROM
    dbo.atable AS t
    CROSS APPLY
    (
      VALUES
      (t.D1id, NULL  , 'D1'),
      (t.D2id, t.D1id, 'D2'),
      (t.D3id, t.D2id, 'D3')
    ) AS v (Nodeid, ParentNodeid, Header)
) AS s
ORDER BY
  D1id ASC,
  D2id ASC,
  D3id ASC
;
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用 GROUP BY 而不是 DISTINCT,从而返回没有派生表的排序后的三列集:

SELECT
  v.Nodeid,
  v.ParentNodeid,
  v.Header
FROM
  dbo.atable AS t
  CROSS APPLY
  (
    VALUES
    (t.D1id, NULL  , 'D1'),
    (t.D2id, t.D1id, 'D2'),
    (t.D3id, t.D2id, 'D3')
  ) AS v (Nodeid, ParentNodeid, Header)
GROUP BY
  t.D1id,
  t.D2id,
  t.D3id,
  v.Nodeid,
  v.ParentNodeid,
  v.Header
ORDER BY
  t.D1id ASC,
  t.D2id ASC,
  t.D3id ASC
;
Run Code Online (Sandbox Code Playgroud)