2

私は多くの XML PATH ステートメントを実行しましたが、これは私をエスケープするか、複数の異なる子を持つことさえできないかもしれません。

最終結果は次のようになります

<Process>
<TaskList>
<SqlTask Name="Get Report Parameters">
    <StoredProcName>GetReportParameters</StoredProcName>
        <ConnectionName>Local</ConnectionName>
        <DataTableName>DistributionList</DataTableName>
        <Parameters>
              <Parameter>
            <Name>ReportName</Name>
            <Value>TheReprot</Value>
            <Type>String</Type>
              </Parameter>
        </Parameters>
  </SqlTask>
  <LoopTask Name="Loop Report Creation" ContainerKey="DistributionList">
  <TaskList>
        <ReportTask Name="Report In Loop">   
    </ReportTask>
</TaskList>
  </LoopTask>
  <SqlTask Name="Get Email Addresses">
    <StoredProcName>GetMailingAddress</StoredProcName>
        <ConnectionName>Local</ConnectionName>
        <DataTableName>EmailList</DataTableName>

  </SqlTask>
  <LoopTask Name="Loop Mail Creation" ContainerKey="EmailList">
<TaskList>
        <MailTask Name="Send Email In Loop">       
        </MailTask>
</TaskList>
  </LoopTask>
</TaskList>
</Process>

以下は、これまでに持っているテストテーブルとデータです。問題は、同じルートの下に異なる子ノードを表示するにはどうすればよいかということです。また、列の値からタグ名を派生させることはできますか?

CREATE TABLE #TASK (
    TaskId INT IDENTITY(1,1)
,    ProcessId INT
,    TaskType VARCHAR(255)
,    TaskName VARCHAR(255)
,    ContainerKey VARCHAR(255)
,    ParentTaskId INT
)

CREATE TABLE #TASK_PARAMETERS 

(
    TaskId INT
,    Name VARCHAR(255)
,    Value VARCHAR(MAX)
,    [Type] VARCHAR(128)
)

CREATE TABLE #TASK_DETAILS
(
    TaskId INT
,    DetailName VARCHAR(255)
,    DetailValue VARCHAR(MAX)
)

DECLARE @TaskId AS INT
DECLARE @ParentTaskId AS INT


INSERT INTO #TASK 
(
    ProcessId
,    TaskType
,    TaskName
,    ContainerKey
,    ParentTaskId
)
VALUES 
(
0
,    'SqlTask'
,    'Get Report Parameters'
,    NULL
,    NULL
)

SET @TaskId = @@IDENTITY

INSERT INTO #TASK_DETAILS
(
    TaskId
,    DetailName
,    DetailValue
)
VALUES 
(
    @TaskId
,    'StoredProceName'
,    'GetReportParamters'
)

INSERT INTO #TASK_DETAILS
(
    TaskId
,    DetailName
,    DetailValue
)
VALUES 
(
    @TaskId
,    'ConnectionName'
,    'Local'
)

INSERT INTO #TASK_DETAILS
(
    TaskId
,    DetailName
,    DetailValue
)
VALUES 
(
    @TaskId
,    'DataTableName'
,    'DistributionList'
)

INSERT INTO #TASK_PARAMETERS 

(
    TaskId
,    Name
,    Value
,    [Type]
)
VALUES 
(
    @TaskId
,    'ReportName'
,    'TheReprot'
,   'String'
)


INSERT INTO #TASK 
(
    ProcessId
,    TaskType
,    TaskName
,    ContainerKey
,    ParentTaskId
)
VALUES 
(
0
,    'LoopTask'
,    'Loop Report Creation'
,    'DistributionList'
,    NULL
)

SET @ParentTaskId = @@IDENTITY


INSERT INTO #TASK 
(
    ProcessId
,    TaskType
,    TaskName
,    ContainerKey
,    ParentTaskId
)
VALUES 
(
0
,    'ReportTask'
,    'Report In Loop'
,    NULL
,    @ParentTaskId
)


INSERT INTO #TASK 
(
    ProcessId
,    TaskType
,    TaskName
,    ContainerKey
,    ParentTaskId
)
VALUES 
(
0
,    'SqlTask'
,    'Get Email Addresses'
,    NULL
,    NULL
)

SET @TaskId = @@IDENTITY

INSERT INTO #TASK_DETAILS
(
    TaskId
,    DetailName
,    DetailValue
)
VALUES 
(
    @TaskId
,    'StoredProceName'
,    'GetMailingAddress'
)

INSERT INTO #TASK_DETAILS
(
    TaskId
,    DetailName
,    DetailValue
)
VALUES 
(
    @TaskId
,    'ConnectionName'
,    'Local'
)

INSERT INTO #TASK_DETAILS
(
    TaskId
,    DetailName
,    DetailValue
)
VALUES 
(
    @TaskId
,    'DataTableName'
,    'EmailList'
)


INSERT INTO #TASK 
(
    ProcessId
,    TaskType
,    TaskName
,    ContainerKey
,    ParentTaskId
)
VALUES 
(
0
,    'LoopTask'
,    'Loop Mail Creation'
,    'EmailList'
,    NULL
)

SET @ParentTaskId = @@IDENTITY

INSERT INTO #TASK 
(
    ProcessId
,    TaskType
,    TaskName
,    ContainerKey
,    ParentTaskId
)
VALUES 
(
0
,    'MailTask'
,    'Send Email In Loop'
,    NULL
,    @ParentTaskId
)


SELECT *
FROM #TASK

SELECT *
FROM #TASK_PARAMETERS 

SELECT *
FROM  #TASK_DETAILS
4

1 に答える 1

1

そうです、あなたのサンプルには克服しなければならない問題がたくさんあります!

まず、答えを教えますが、階層的に正しく処理するには再帰関数でなければならないことに注意してください。そのため、提供したテストデータは、一時的ではなく永続的なテーブルで作成する必要がありました (より単純です)。問題を解決するために私が使用したいくつかの便利なテクニックを指摘します。

ALTER FUNCTION GetTasks (@ParentId varchar(255)= NULL) 
RETURNS
XML
BEGIN
DECLARE @ReturnXML XML

SELECT @ReturnXML = 
(
    SELECT
    (
        SELECT 
            CONVERT(XML,
                --Main task start tag
                '<'+master_t.TaskType+' Name="'+master_t.TaskName+'">'+ 
                    CONVERT(VARCHAR(MAX),
                        (

                            SELECT
                            dbo.GetTasks(master_t.TaskId),
                            (
                                SELECT 
                                    CONVERT(XML,'<'+DetailName+'>'+DetailValue+'</'+DetailName+'>')
                                FROM
                                    TASK_DETAILS t 
                                WHERE
                                    TaskId = master_t.TaskId
                                FOR XML PATH(''),Type
                            ),
                            (
                                SELECT Name,Value,Type FROM TASK_PARAMETERS t 
                                WHERE TaskId=master_t.TaskId
                                FOR XML PATH('Parameter'),Type
                            ) 'Parameters'
                            FOR XML PATH(''),Type 
                        )
                    )
                    +
                --Main task end tag
                '</'+master_t.TaskType+'>'
            )
        FROM 
            TASK master_t
        WHERE 
            --Effectively ignore the parentId field if it is not passed.
            ISNULL(ParentTaskId,'') = CASE WHEN @ParentId IS NULL THEN '' ELSE @ParentId END


        FOR XML PATH(''),Type
    ) 'TaskList'  FOR XML PATH(''),Type
) 

RETURN @ReturnXML
END
GO

この関数を次のように呼び出します。

SELECT dbo.GetTasks(NULL)

私が注目に値すると思うテクニックは次のとおりです。

a) 文字列から作成するだけで手動で xml ノードを作成できます。これは、ノード名がテーブルにある場合に便利です。注意しなければならない唯一のことは、ブロックの前後に開始タグと終了タグを配置するには、おそらく最初にブロックを文字列に変換し、タグを付けてから、全体を xml に変換する必要があるということです (断片的なconvert-to-xml 関数は整形式の XML を提供することを期待するため、機能しません。

b) すべてのサブタグの周りにタグを作成するために、括弧内に物を入れ子にする必要がある場合があります...例はこれをより明確にします:

 SELECT 
    TaskName
    FROM TASK t
    FOR XML PATH('SomeRoot')

次の結果が得られます。

<SomeRoot>
  <TaskName>Get Report Parameters</TaskName>
</SomeRoot>
<SomeRoot>
  <TaskName>Loop Report Creation</TaskName>
</SomeRoot>
<SomeRoot>
  <TaskName>Report In Loop</TaskName>
</SomeRoot>
<SomeRoot>
  <TaskName>Get Email Addresses</TaskName>
</SomeRoot>
<SomeRoot>
  <TaskName>Loop Mail Creation</TaskName>
</SomeRoot>
<SomeRoot>
  <TaskName>Send Email In Loop</TaskName>
</SomeRoot>

その周りに「SomeRoot」を表示するには、次のようにします。

SELECT 
(
    SELECT 
        TaskName
    FROM TASK t
    FOR XML PATH(''),Type
) 
FOR XML PATH('SomeRoot')

ノード名が静的な場合 (XML PATH('') ,Typeに注意してください。これにより、基本的に、XML パスが XML 型のデータを返してさらに処理し、エスケープしないことが保証されます)

ノード名が静的でない場合は、文字列との間で変換して機能させる必要があるため、このような問題に悩まされています。

SELECT 
    CONVERT(XML,
        '<'+DynamicName+'>' + 
        CONVERT(VARCHAR(MAX),
                (
                    SELECT 
                        TaskName
                    FROM TASK t
                    FOR XML PATH(''),Type
                )
            ) +
            '</'+DynamicName+'>'  
    )
FROM
    (SELECT 'Test' as DynamicName) a

c) 異なる子タグを同じレベルに表示することに関するあなたの質問に関しては、それはかなり些細なことであり、選択の複数のレイヤーの通常の問題は xml の問題ではなくなることを覚えておく必要があります。単一の xml オブジェクト。次に、XML PATH を使用して、これらの結果をツリーに結合することもできます。

例えば

SELECT 
    (SELECT top 1 * FROM TASK FOR XML PATH(''),Type),
    (SELECT top 1 * FROM TASK_DETAILS FOR XML PATH(''),Type)

2 列の 1 つの行を返しますが、XML PATH('') を全体に適用すると、それらは同じレベルで結合されます

SELECT 
    (SELECT top 1 * FROM TASK FOR XML PATH(''),Type),
    (SELECT top 1 * FROM TASK_DETAILS FOR XML PATH(''),Type)
FOR XML PATH('Root')    

d) XML PATH による場合、列名はノードに変換されます。列に適切な xsl パスであるエイリアスを与えるだけなので、属性は非常に簡単です。そのために、この例では、もう一度文字列から xml を作成しました。これは偶然にも、動的ノード名が非常に悪い考えである理由です-基本的に、ルーチンがテーブル内のデータを介して新しい属性名とノード名を作成できるようにします...これは、ルーチンの適切なスキーマを作成できないことを意味しますテーブルに含まれる可能性のあるデータが事前にわかりません...

先に進む:)

したがって、これらの構成要素が与えられた場合、最も簡単な方法は、最も深いレベルから作業し、ブロックごとに構築してから、上記のように組み合わせることです。

私はあなたのクエリに対してそれを行いましたが、最終的にそれを階層的に機能させるには(つまり、n ネストされたレベル)、XML を返す関数として記述する必要があることに気付きました。結果セットをフィルタリングします)。ヒエラルキーが不規則で循環している場合、これは恐ろしい死に方をします。

わかりました-うまくいけば、そこにあなたが働ける何かがあるでしょう. これは純粋に XML PATH() 指向のソリューションです。さまざまな状況で役立つ代替 XML メソッドがあります。

于 2010-07-14T13:31:06.270 に答える