2016-05-06 5 views
3

私は、かなりの時間がかかる「ブラックボックス」プロセスの代替ソリューションを調査することを任されましたが、その中で変更または改善することはできません。ネストされた要素を含むSQLテーブル内のXML

私がしようとしているのは、テキストフィールド(変換するためにCASTを使用)として現在保持されているテーブル内のXMLから情報を抽出することです。複数の行があり、XMLには属性を含むいくつかのネストされた要素が含まれています。次のように1行分の格納されたXMLの

一例である:私は抽出するために必要なもの

<offerContext weightExpr="90"> 
    <filter label="Description of XML held here"> 
    <where displayFilter="Second description of XML held here" filterName="backGroundFilterFrm" id="13706004488"> 
     <condition boolOperator="AND" compositeKey="" dependkey="FK_Rcp_Brand" enabledIf="" expr="@BrandId = 1" internalId="-1548698833" /> 
     <condition boolOperator="AND" compositeKey="FK_Rcp_Brand" dependkey="" expr="FK_Rcp_Brand = '1'" internalId="1370600592" /> 
     <condition boolOperator="AND" compositeKey="" dependkey="" expr="proposition" internalId="1370600625" setOperator="EXISTS"> 
     <condition boolOperator="AND" compositeKey="" dependkey="" expr="@status = 3" internalId="1370600632" /> 
     <condition boolOperator="AND" compositeKey="" dependkey="" expr="[offer/@name] = 'Spend20get5Off'" internalId="1370600644" /> 
     <condition compositeKey="" dependkey="" expr="[offerSpace/@channel] = 0" internalId="1370600655" /> 
     </condition> 
     <condition boolOperator="AND" compositeKey="" dependkey="" enabledIf="" expr="proposition" internalId="1372382776" setOperator="NOT EXISTS"> 
     <condition boolOperator="AND" compositeKey="" dependkey="" enabledIf="" expr="[offer/@name] = 'Spend20get5Off'" internalId="1372382779" /> 
     <condition boolOperator="AND" compositeKey="" dependkey="" enabledIf="" expr="@eventDate &gt;= DaysAgo(21)" internalId="1372382782" /> 
     <condition boolOperator="AND" compositeKey="" dependkey="" enabledIf="" expr="[offerSpace/@channel] = 0" internalId="1372382786" /> 
     </condition> 
    </where> 
    <humanCond>Query: Description of XML held here</humanCond> 
    </filter> 
    <extension useBuildPropositionsScript="false" /> 
</offerContext> 

はofferContext要素からweightexprあります。これと並んで、各条件要素からbooloperator、compositekey、dependkey、expr、internalIdが必要です。子要素が親要素にリンクされるようにこれらを抽出する必要があります。これが私がいくつかの問題を抱えているところです。私は、両方の要素を1つの行にプルする次のようなことがありますが、後でいくつかの操作が必要になります(問題はありませんが、これを行うための良い方法があることを知りたがっています)。

私がこれまででてきたコード:私が権利を持っていることが重要である理由

;WITH contexts AS 
    (
    SELECT a.iOfferId, a.iOfferContextId, a.mdata, CONVERT(xml,a.mdata) AS XMLmData 
    FROM NmsOfferContext a 
    ) 
SELECT 
    iOfferId 
    ,iOfferContextId 
    ,p2.value('(@weightExpr)[1]', 'nvarchar(max)') AS dweight 
    ,p2.value('(@boolOperator)[1]', 'nvarchar(max)') AS boolOperator2 
    ,p2.value('(@dependKey)[1]', 'nvarchar(max)') AS dependKey2 
    ,p2.value('(@expr)[1]', 'nvarchar(max)')   AS expr2 
    ,p2.value('(@setOperator)[1]', 'nvarchar(max)') AS setoperator2 
    ,p2.value('(@internalId)[1]', 'nvarchar(max)') AS internalID2 
    ,p3.value('(@boolOperator)[1]', 'nvarchar(max)') AS boolOperator3 
    ,p3.value('(@dependKey)[1]', 'nvarchar(max)') AS dependKey3 
    ,p3.value('(@expr)[1]', 'nvarchar(max)')   AS expr3 
    ,p3.value('(@setOperator)[1]', 'nvarchar(max)') AS setoperator3 
    ,p3.value('(@internalId)[1]', 'nvarchar(max)') AS internalID3 
FROM contexts 
CROSS APPLY XMLmData.nodes('/offerContext/*/*/condition') t(p2) 
CROSS APPLY XMLmData.nodes('/offerContext/*/*/condition/condition') t2(p3) 
ORDER BY iOfferContextId, 
    p2.value('(@internalId)[1]', 'nvarchar(max)'), 
    p3.value('(@internalId)[1]', 'nvarchar(max)') 

最終的に私は、したがって、exprの値に基づいて、SQLクエリを構築するために必要とWHERE句のためbooloperatorを使用して(私はinternalId属性でも実現できると信じている)要素の順序ですが、親と子の関係を維持することは私が助けが必要なところです。

私は正しい軌道に乗っているなら、どんな助けもありがたいと思います。何か明確な説明が必要な場合は、お気軽にお問い合わせください。

ありがとうございます。

+0

あなたの例では、条件の1子レベルを示しています...もっとあるかもしれない? – Shnugo

+0

私の知る限り、2つのレベルしかありません。私は確かに今のところこれらのレベルに限定しています。 –

答えて

2

ノードのレベル間の関係を構築するために、再帰的なCTEを使用してXMLを細断できます。

declare @X xml = ' 
<offerContext weightExpr="90"> 
    <filter label="Description of XML held here"> 
    <where displayFilter="Second description of XML held here" filterName="backGroundFilterFrm" id="13706004488"> 
     <condition boolOperator="AND" compositeKey="" dependkey="FK_Rcp_Brand" enabledIf="" expr="@BrandId = 1" internalId="-1548698833" /> 
     <condition boolOperator="AND" compositeKey="FK_Rcp_Brand" dependkey="" expr="FK_Rcp_Brand = ''1''" internalId="1370600592" /> 
     <condition boolOperator="AND" compositeKey="" dependkey="" expr="proposition" internalId="1370600625" setOperator="EXISTS"> 
     <condition boolOperator="AND" compositeKey="" dependkey="" expr="@status = 3" internalId="1370600632" /> 
     <condition boolOperator="AND" compositeKey="" dependkey="" expr="[offer/@name] = ''Spend20get5Off''" internalId="1370600644" /> 
     <condition compositeKey="" dependkey="" expr="[offerSpace/@channel] = 0" internalId="1370600655" /> 
     </condition> 
     <condition boolOperator="AND" compositeKey="" dependkey="" enabledIf="" expr="proposition" internalId="1372382776" setOperator="NOT EXISTS"> 
     <condition boolOperator="AND" compositeKey="" dependkey="" enabledIf="" expr="[offer/@name] = ''Spend20get5Off''" internalId="1372382779" /> 
     <condition boolOperator="AND" compositeKey="" dependkey="" enabledIf="" expr="@eventDate &gt;= DaysAgo(21)" internalId="1372382782" /> 
     <condition boolOperator="AND" compositeKey="" dependkey="" enabledIf="" expr="[offerSpace/@channel] = 0" internalId="1372382786" /> 
     </condition> 
    </where> 
    <humanCond>Query: Description of XML held here</humanCond> 
    </filter> 
    <extension useBuildPropositionsScript="false" /> 
</offerContext>'; 

with A as 
(
    select T.X.value('@weightExpr', 'int') as weightExpr, 
     T.X.query('filter/where/condition') as C, 
     cast(null as int) as internalID, 
     cast(null as int) as internalParentID, 
     cast(null as varchar(10)) as boolOperator, 
     cast(null as varchar(20)) as dependKey, 
     cast(null as varchar(50)) as expr 
    from @X.nodes('/offerContext') as T(X) 
    union all 
    select null, 
     T.X.query('condition'), 
     T.X.value('@internalId', 'int'), 
     A.internalID, 
     T.X.value('@boolOperator', 'varchar(10)'), 
     T.X.value('@dependkey', 'varchar(100)'), 
     T.X.value('@expr', 'varchar(100)') 
    from A 
    cross apply A.C.nodes('condition') as T(X) 
) 
select A.weightExpr, 
     A.internalID, 
     A.internalParentID, 
     A.boolOperator, 
     A.dependKey, 
     A.expr 
from A 
order by A.internalID 

結果:

weightExpr internalID internalParentID boolOperator dependKey  expr 
---------- ----------- ---------------- ------------ ------------- -------------------------------- 
90   NULL  NULL    NULL   NULL   NULL 
NULL  -1548698833 NULL    AND   FK_Rcp_Brand @BrandId = 1 
NULL  1370600592 NULL    AND      FK_Rcp_Brand = '1' 
NULL  1370600625 NULL    AND      proposition 
NULL  1370600632 1370600625  AND      @status = 3 
NULL  1370600644 1370600625  AND      [offer/@name] = 'Spend20get5Off' 
NULL  1370600655 1370600625  NULL      [offerSpace/@channel] = 0 
NULL  1372382776 NULL    AND      proposition 
NULL  1372382779 1372382776  AND      [offer/@name] = 'Spend20get5Off' 
NULL  1372382782 1372382776  AND      @eventDate >= DaysAgo(21) 
NULL  1372382786 1372382776  AND      [offerSpace/@channel] = 0 

ソースがテーブルである場合の書き換え。

with A as 
(
    select Y.offerID, 
     T.X.value('@weightExpr', 'int') as weightExpr, 
     T.X.query('filter/where/condition') as C, 
     cast(null as int) as internalID, 
     cast(null as int) as internalParentID, 
     cast(null as varchar(10)) as boolOperator, 
     cast(null as varchar(20)) as dependKey, 
     cast(null as varchar(50)) as expr 
    from dbo.YourTable as Y 
    cross apply Y.X.nodes('/offerContext') as T(X) 
    union all 
    select A.offerID, 
     null, 
     T.X.query('condition'), 
     T.X.value('@internalId', 'int'), 
     A.internalID, 
     T.X.value('@boolOperator', 'varchar(10)'), 
     T.X.value('@dependkey', 'varchar(20)'), 
     T.X.value('@expr', 'varchar(50)') 
    from A 
    cross apply A.C.nodes('condition') as T(X) 
) 
select A.offerID, 
     A.weightExpr, 
     A.internalID, 
     A.internalParentID, 
     A.boolOperator, 
     A.dependKey, 
     A.expr 
from A 
order by A.offerID, 
     A.internalID 
+0

応答に時間を費やしてくれたMikaelに感謝します。これはすばらしいですが、XMLがテーブル内の列、たとえばofferXMLであり、別のintフィールドofferIDを関連付ける必要がある場合は、ソリューションIDごとにofferIDとシュレッドの両方を選択する方法を教えてください。ソリューションを使用するには、カーソルを適用するか、必要なデータを作成するための関数としてソリューションを使用する必要があります。関数が最良のアプローチであると思われます。 –

+0

@MattPaine再帰的なCTEのアンカー部分の小さな書き換え。答えを更新しました。 –

+0

おかげさまでミカエル、私はそれを試して、私がどのように乗っているかを教えてあげます。 –

1

これは再帰的な方法よりも簡単な別の方法です。これはOPのコメントに基づいており、少なくとも今のところは2レベル以下です。最初に

は、最初のレベルの条件が取得され、あるとしてその内側の第2レベルの条件はを取られて行きます。彼らは出現順に番号が付けられています。

第2段階では、第2レベルの条件が適用されます。両親に分割された出現順に再び番号が付けられます。

最後の二つの選択は、UNION句と条件の位置によってソートし得る:

DECLARE @xml XML= 
'<offerContext weightExpr="90"> 
    <filter label="Description of XML held here"> 
    <where displayFilter="Second description of XML held here" filterName="backGroundFilterFrm" id="13706004488"> 
     <condition boolOperator="AND" compositeKey="" dependkey="FK_Rcp_Brand" enabledIf="" expr="@BrandId = 1" internalId="-1548698833" /> 
     <condition boolOperator="AND" compositeKey="FK_Rcp_Brand" dependkey="" expr="FK_Rcp_Brand = ''1''" internalId="1370600592" /> 
     <condition boolOperator="AND" compositeKey="" dependkey="" expr="proposition" internalId="1370600625" setOperator="EXISTS"> 
     <condition boolOperator="AND" compositeKey="" dependkey="" expr="@status = 3" internalId="1370600632" /> 
     <condition boolOperator="AND" compositeKey="" dependkey="" expr="[offer/@name] = ''Spend20get5Off''" internalId="1370600644" /> 
     <condition compositeKey="" dependkey="" expr="[offerSpace/@channel] = 0" internalId="1370600655" /> 
     </condition> 
     <condition boolOperator="AND" compositeKey="" dependkey="" enabledIf="" expr="proposition" internalId="1372382776" setOperator="NOT EXISTS"> 
     <condition boolOperator="AND" compositeKey="" dependkey="" enabledIf="" expr="[offer/@name] = ''Spend20get5Off''" internalId="1372382779" /> 
     <condition boolOperator="AND" compositeKey="" dependkey="" enabledIf="" expr="@eventDate &gt;= DaysAgo(21)" internalId="1372382782" /> 
     <condition boolOperator="AND" compositeKey="" dependkey="" enabledIf="" expr="[offerSpace/@channel] = 0" internalId="1372382786" /> 
     </condition> 
    </where> 
    <humanCond>Query: Description of XML held here</humanCond> 
    </filter> 
    <extension useBuildPropositionsScript="false" /> 
</offerContext>'; 

WITH AllConditionsLevel1 AS 
(
    SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS CondLevel1_Position 
      ,CAST(0 AS BIGINT) AS CondLevel2_Position 
      ,1 AS CondLevel 
      ,@xml.value('(offerContext/@weightExpr)[1]','int') AS OfferContext_WeightExpr 
      ,@xml.value('(offerContext/filter/@label)[1]','varchar(max)') AS Filter_Label 
      ,@xml.value('(offerContext/where/@displayFilter)[1]','varchar(max)') AS Where_DisplayFilter 
      ,@xml.value('(offerContext/where/@filterName)[1]','varchar(max)') AS Where_FilterName 
      ,@xml.value('(offerContext/where/@id)[1]','varchar(max)') AS Where_Id 
      ,CondLevel1.value('@boolOperator','varchar(max)') AS Cond_BoolOperator 
      ,CondLevel1.value('@compositeKey','varchar(max)') AS Cond_CompositeKey 
      ,CondLevel1.value('@dependkey','varchar(max)') AS Cond_DependKey 
      ,CondLevel1.value('@expr','varchar(max)') AS Cond_Expr 
      ,CondLevel1.value('@internalId','varchar(max)') AS Cond_InternalId 
      ,CondLevel1.value('@setOperator','varchar(max)') AS Cond_SetOperator 
      ,CondLevel1.value('@enabledIf','varchar(max)') AS Cond_EnabledIf 
      ,CondLevel1.query('*') AS CondLevel2Nodes 
    FROM @xml.nodes('offerContext/filter/where/condition') AS A(CondLevel1) 
) 
SELECT * 
FROM 
(
    SELECT * FROM AllConditionsLevel1 
    UNION ALL 
    SELECT CondLevel1_Position 
      ,ROW_NUMBER() OVER(PARTITION BY CondLevel1_Position ORDER BY (SELECT NULL)) 
      ,2 
      ,OfferContext_WeightExpr 
      ,Filter_Label 
      ,Where_DisplayFilter 
      ,Where_FilterName 
      ,Where_Id 
      ,CondLevel2.value('@boolOperator','varchar(max)') 
      ,CondLevel2.value('@compositeKey','varchar(max)') 
      ,CondLevel2.value('@dependkey','varchar(max)') 
      ,CondLevel2.value('@expr','varchar(max)') 
      ,CondLevel2.value('@internalId','varchar(max)') 
      ,CondLevel2.value('@setOperator','varchar(max)') 
      ,CondLevel2.value('@enabledIf','varchar(max)') 
      ,NULL 
    FROM AllConditionsLevel1 
    CROSS APPLY CondLevel2Nodes.nodes('condition') AS B(CondLevel2) 
) AS tbl 
ORDER BY CondLevel1_Position,CondLevel2_Position 
関連する問題