11

DB に隣接リストがあり、SQL SP を介して XML 形式のデータをクライアントに配信したいと考えています。CTE と FOR XML を使用しようとしていますが、XML ノードをネストできません。

参考までに、これはサイト マップを表します。

テーブル構造:

CREATE TABLE [dbo].[PageHierarchy](
    [ModuleId] [int] NOT NULL,
    [PageId] [int] IDENTITY(1,1) NOT NULL,
    [ParentPageId] [int] NULL,
    [PageUrl] [nvarchar](100) NULL,
    [PageTitle] [nvarchar](50) NOT NULL,
    [PageOrder] [int] NULL)

そしてCTEの始まり:

;WITH cte AS
(
    select * from PageHierarchy where ParentPageId is null
    union all
    select child.* from PageHierarchy child inner join cte parent on parent.PageId = child.ParentPageId
)
SELECT ModuleId, PageId, ParentPageId, PageUrl, PageTitle, PageOrder FROM cte
group by ModuleId, PageId, ParentPageId, PageUrl, PageTitle, PageOrder
order by PageOrder
for xml auto, root ('bob')

次のような XML が生成されます。

<bob>
  <cte ModuleId="1" PageId="1" PageUrl="~/Admin/" PageTitle="Administration" PageOrder="1000" />
  <cte ModuleId="1" PageId="4" ParentPageId="1" PageTitle="Manage Users" PageOrder="1030" />
  <cte ModuleId="1" PageId="5" ParentPageId="4" PageUrl="~/Admin/AddUser" PageTitle="Add Users" PageOrder="1040" />
  <cte ModuleId="1" PageId="8" ParentPageId="4" PageUrl="~/Admin/EditUser" PageTitle="Edit/Search User" PageOrder="1070" />
</bob>

私が欲しいのは、次のような XML です。

<bob>
  <cte ModuleId="1" PageId="1" PageUrl="~/Admin/" PageTitle="Administration" PageOrder="1000" />
  <cte ModuleId="1" PageId="4" ParentPageId="1" PageTitle="Manage Users" PageOrder="1030" >
    <cte ModuleId="1" PageId="5" ParentPageId="4" PageUrl="~/Admin/AddUser" PageTitle="Add Users" PageOrder="1040" />
    <cte ModuleId="1" PageId="8" ParentPageId="4" PageUrl="~/Admin/EditUser" PageTitle="Edit/Search User" PageOrder="1070" />
  </cte>
</bob>

問題はCTEではなく選択にあると思いますが、どこから修正を開始すればよいかわかりません。また、ネスティングがどれくらい深くなるかわからないので、少なくとも 10 レベルの深さをサポートする必要があると想定しています。

編集 1:
近づいていると思います...このページを見て、UDF を作成しましたが、まだいくつかの問題があります:

CREATE FUNCTION PageHierarchyNode(@PageId int)
RETURNS XML
WITH RETURNS NULL ON NULL INPUT 
BEGIN RETURN 
  (SELECT ModuleId AS "@ModuleId", PageId AS "@PageId",
    ParentPageId AS "@ParentPageId", PageUrl AS "@PageUrl",
    PageTitle AS "@PageTitle", PageOrder AS "@PageOrder", 
      CASE WHEN ParentPageId=@PageId
      THEN dbo.PageHierarchyNode(PageId)
      END
   FROM dbo.PageHierarchy WHERE ParentPageId=@PageId
   FOR XML PATH('Page'), TYPE)
END

および UDF を呼び出す SQL

SELECT ModuleId AS "@ModuleId", PageId AS "@PageId",
    ParentPageId AS "@ParentPageId", PageUrl AS "@PageUrl",
    PageTitle AS "@PageTitle", PageOrder AS "@PageOrder", 
    dbo.PageHierarchyNode(PageId)
FROM PageHierarchy
FOR XML PATH('Page'), ROOT('SiteMap'), TYPE

これは私のためにXMLをネストしますが、それは私が望むものではないノードを複製しています..

編集2:

UDF を呼び出す SELECT に WHERE 句を追加する必要がありました。

...
WHERE ParentPageId IS NULL
4

3 に答える 3

6

再帰的 CTE は、「入れ子」のように再帰的ではありません。動作が異なり、実行しようとしていることが CTE では機能しません。(それらは常に末尾再帰的であると考えてください。)

SQL Server で再帰的な XML を構築する唯一の方法は、ノードを再帰的にレンダリングするスカラー関数を作成することです。関数は再帰呼び出しを行うことができるため、これは期待どおりに機能します。

于 2013-02-08T04:59:42.293 に答える