嵌套 XML 查询中所有项目的项目索引

JNK*_*JNK 5 xml sql-server sql-server-2008-r2

我需要构建一个带有父记录和 1..N 个相关子记录的 XML 包。

子记录是父节点下的一个节点,每个父节点可能有一个或多个子记录。在同一个查询中也可以有多个父项。

上面的查询我没有问题。

我还要求为每条记录(父项和子项)提供一个唯一的基于 0 的索引。我可以ROW_NUMBER为每个子查询使用 with ,但无法找到一种方法来为整个查询中的每条记录获取唯一索引。

在这里摆弄示例数据和工作查询。

(请注意,SQLFiddle 不会以非常易于阅读的格式显示 XML,因此您可能希望在本地 SSMS 中运行它。)

工作SSMS代码如下:

BEGIN TRY
    DROP TABLE #Child
    DROP TABLE #Parent
END TRY
BEGIN CATCH
END CATCH

CREATE TABLE #Parent 
    (RecId int PRIMARY KEY NOT NULL, 
     PersonName varchar(100), Age int)
CREATE TABLE #Child 
    (ChildID int identity PRIMARY KEY NOT NULL,
     ParentRecId int FOREIGN KEY REFERENCES #Parent(RecId), 
     SalesAmt money)

INSERT INTO #Parent
  (RecID, PersonName, Age)
VALUES
  (1, 'Aaron Bertrand', 99),
  (2, 'Paul White', 20),
  (3, 'JNK', 33)

INSERT INTO #Child
  (ParentRecID, SalesAmt)
VALUES
  (1, 10.00),
  (1, 20.00),
  (2, 15.15),
  (2, 100.00),
  (3, 0.00)

SELECT
  RecId as 'RID',
  PersonName as 'PNAM',
  Age,
  (
    SELECT 
      C.SalesAmt as 'SAMT',
      (ROW_NUMBER() OVER (ORDER BY ParentRecId) - 1) as 'Index'
    FROM
      #Child C
    WHERE
      C.ParentRecId = P.RecId
    FOR XML PATH ('ChildRec'), ROOT ('ChildRecs'), TYPE
  )
FROM
  #Parent P
FOR XML PATH ('Parent'), ROOT ('Parents'), TYPE
Run Code Online (Sandbox Code Playgroud)

如何获取此 XML 包的所有父记录和子记录的唯一索引?

JNK*_*JNK 3

我找到了答案 - 我需要创建一个CTE使用所有子记录和父记录的并集并创建一个ROW_NUMBER(),然后JOIN创建一个CTE以获得ROW_NUMBER()在所有记录中唯一的值。

解决方案在这里摆弄。

粘贴到 SSMS 的完整解决方案:

BEGIN TRY
    DROP TABLE #Child
    DROP TABLE #Parent
END TRY
BEGIN CATCH
END CATCH

CREATE TABLE #Parent 
    (RecId int PRIMARY KEY NOT NULL, 
     PersonName varchar(100), Age int)
CREATE TABLE #Child 
    (ChildID int identity PRIMARY KEY NOT NULL,
     ParentRecId int FOREIGN KEY REFERENCES #Parent(RecId), 
     SalesAmt money)

INSERT INTO #Parent
  (RecID, PersonName, Age)
VALUES
  (1, 'Aaron Bertrand', 99),
  (2, 'Paul White', 20),
  (3, 'JNK', 33)

INSERT INTO #Child
  (ParentRecID, SalesAmt)
VALUES
  (1, 10.00),
  (1, 20.00),
  (2, 15.15),
  (2, 100.00),
  (3, 0.00)

;WITH IDs AS
(
    SELECT
       RN = (ROW_NUMBER() OVER (ORDER BY  RecId,CASE WHEN ChildId IS NULL THEN 0 ELSE 1 END) -1),
       RecId,
       ChildId
    FROM
       (
       SELECT
          RecId, ChildId = NULL
       FROM
          #Parent
       UNION ALL
       SELECT
          RecId, ChildId
       FROM 
          #Parent P
       INNER JOIN
          #Child C
              ON C.ParentRecId = P.RecId) x
)

SELECT
  P.RecId as 'RID',
  P.PersonName as 'PNAM',
  P.Age,
  I.RN as 'Index',
  (
    SELECT 
      C.SalesAmt as 'SAMT',
      I.RN as 'Index'
    FROM
      #Child C
    INNER JOIN
       IDs I
          ON I.ChildId = C.ChildID
    WHERE
      C.ParentRecId = P.RecId
    FOR XML PATH ('ChildRec'), ROOT ('ChildRecs'), TYPE
  )
FROM
  #Parent P
INNER JOIN
    IDs I
       ON I.RecId = P.RecId
       AND I.ChildId IS NULL
FOR XML PATH ('Parent'), ROOT ('Parents'), TYPE
Run Code Online (Sandbox Code Playgroud)