1

次の状況を考えてみましょう。私は次の表を持っています

CREATE TABLE [dbo].[GoldenEgg]
(       
    rowIndex int NOT NULL IDENTITY(1,1),    
    AccountNumber varchar(256) NULL,            
    SubscriptionID int NOT NULL,            
    SubscriptionData_XML xml NULL,
    SubscriptionData_AFTER_XML NULL     

    CONSTRAINT [PK_GoldenEgg] 
        PRIMARY KEY CLUSTERED ([rowIndex] ASC)
                    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
                          IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
                          ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GoldenEgg サンプル データ:

ゴールデンエッグ テーブル

SubscriptionData_XMLSubscriptionID 6070 のデータ:

<NVPList xmlns="http://www.whatevernamspace.com/v1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <Item>
    <Name>AccountNumbers</Name>
    <Value>
      <ValueItem>39448474</ValueItem>     
    </Value>
  </Item>
</NVPList>

各 SubscriptionID のすべてのアカウント番号を SubscriptionData_XML 列の既存の xml<Value>ノードに追加したいのですが、xml に既に存在するアカウント番号を追加したくありません。

したがって、SubscriptionID 6070 のアカウント番号 39448474 は、次のように xml に 1 回だけリストする必要があります。

<NVPList xmlns="http://www.whatevernamspace.com/v1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <Item>
    <Name>AccountNumbers</Name>
    <Value>
      <ValueItem>39448474</ValueItem>
      <ValueItem>56936495</ValueItem>
      <ValueItem>70660044</ValueItem>
      <ValueItem>41447395</ValueItem>    
    </Value>
  </Item>
</NVPList>
4

2 に答える 2

2

XML 内に他のノードがない場合は、FLWOR-queryを選択できます。

いくつかのヒント:

  • まず、モックアップテーブルを作成し、データを入力します。
  • 更新可能な CTEを使用してデータを収集します
  • 名前空間なしでFOR XML-sub-selectを使用して、実際の XML に既に存在する ID を気にせずにノードを構築します。<Value>
  • を使用してFLWOR-query()、作成したばかりの値ノードから完全な XML を構築します
  • この CTE は更新可能であるため、UPDATE
  • SELECT * FROM @tblすべてAFTER_XMLが満たされていることを最後にあなたに示します

これを試して:

DECLARE @tbl TABLE(rowIndex INT IDENTITY,AccountNumber INT,SubscriptionID INT, SubscriptionData_XML XML,SubscriptionData_AFTER_XML XML);
INSERT INTO @tbl VALUES
 (1111,6070,N'<NVPList xmlns="http://www.whatevernamspace.com/v1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <Item>
    <Name>AccountNumbers</Name>
    <Value>
      <ValueItem>39448474</ValueItem>     
    </Value>
  </Item>
</NVPList>',NULL)
,(2222,6070,NULL,NULL)
,(3333,6070,NULL,NULL)
,(4444,6070,NULL,NULL)
,(5555,6071,N'<NVPList xmlns="http://www.whatevernamspace.com/v1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <Item>
    <Name>AccountNumbers</Name>
    <Value>
      <ValueItem>39448474</ValueItem>     
    </Value>
  </Item>
</NVPList>',NULL)
,(6666,6071,NULL,NULL)
,(7777,6071,NULL,NULL)
,(8888,6071,NULL,NULL);

-- ここで更新可能な CTE を開始します

WITH UpdateableCTE AS
(
    SELECT t1.rowIndex
          ,t1.SubscriptionData_AFTER_XML
          ,(
            SELECT t2.AccountNumber AS ValueItem
            FROM @tbl AS t2
            WHERE t2.SubscriptionID=t1.SubscriptionID
            FOR XML PATH(''),ROOT('Value'),TYPE
           ).query
                (N'declare default element namespace "http://www.whatevernamspace.com/v1";
                   let $nd:=/*:Value
                   return
                   <NVPList>
                       <Item>
                          <Name>{sql:column("XmlName")}</Name>
                          <Value>
                           {
                           for $vi in $nd/*:ValueItem
                           return <ValueItem>{$vi/text()}</ValueItem>
                           }
                          </Value>
                       </Item>
                   </NVPList>
                  '
                ) AS NewXML

    FROM @tbl AS t1
    CROSS APPLY( SELECT t1.SubscriptionData_XML.value('(//*:Name)[1]','nvarchar(max)') AS XmlName) AS x
    WHERE SubscriptionData_XML IS NOT NULL
)

-- UPDATE ステートメント

UPDATE UpdateableCTE SET SubscriptionData_AFTER_XML=NewXML
FROM UpdateableCTE;

-- 成功を確認するための SELECT

SELECT * FROM @tbl
于 2016-11-10T09:55:38.730 に答える
1

このタスクはUPDATE、xmlmodify()メソッドを使用した sql ステートメントで、ループを使用せずに達成できました。ソリューションの内訳は次のとおりです。

1) SubscriptionID のすべての AccountNumbers を取得し、それらを xml<ValueItem>ノードにフォーマットする必要がありました。

SQL クエリ 1:

SELECT 
ge.SubscriptionID,
CAST((SELECT DISTINCT ValueItem = ISNULL(ge2.AccountNumber,'')
        FROM dbo.GoldenEgg ge2
        WHERE ge2.SubscriptionID = ge.SubscriptionID                        
        FOR XML PATH('')) AS xml) AS AccountNumberXml
FROM dbo.GoldenEgg ge
WHERE ge.SubscriptionData_XML IS NOT NULL

SQL クエリ 1 の結果:
AccountNumberXml

SQL クエリ 1 XML 結果(SubscriptionID 6070):

<ValueItem>39448474</ValueItem>
<ValueItem>41447395</ValueItem>
<ValueItem>56936495</ValueItem>
<ValueItem>70660044</ValueItem>


2) AccountNumbers を 1 つの値で取得したので、xmlmodify()メソッドを使用して、値をxml ノードAccountNumberXmlの最後の位置に挿入できます。ステートメントを<Value>使用してこれを行います。また、何かを行う前に、最初に SubscriptionData_AFTER_XML を SubscriptionData_XML と等しく設定していることにも注意してください。UPDATEINNER JOIN

SQL クエリ 2:

UPDATE ge
    SET SubscriptionData_AFTER_XML.modify
    ('declare default element namespace "http://www.whatevernamspace.com/v1";
      insert sql:column("t1.AccountNumberXml") as last into (/NVPList/Item/Value)[1]')          
    FROM dbo.GoldenEgg ge
    INNER JOIN (SELECT 
                ge2.SubscriptionID,
                CAST((SELECT DISTINCT ValueItem = ISNULL(ge1.AccountNumber,'')
                        FROM dbo.GoldenEgg ge1                                              
                        WHERE ge1.SubscriptionID = ge2.SubscriptionID                       
                        FOR XML PATH('')) AS xml) as AccountNumberXml
                FROM dbo.GoldenEgg ge2
                WHERE ge2.SubscriptionData_AFTER_XML IS NOT NULL) t1 ON t1.SubscriptionID = ge.SubscriptionID
    WHERE ge.SubscriptionData_AFTER_XML IS NOT NULL

SQL クエリ 2 の結果: ここに画像の説明を入力

SQL クエリ 2 XML 結果(SubscriptionID 6070 SubscriptionData_AFTER_XML 列):

<NVPList xmlns="http://www.whatevernamspace.com/v1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <Item>
    <Name>AccountNumbers</Name>
    <Value>
      <ValueItem>39448474</ValueItem>
      <ValueItem xmlns="">39448474</ValueItem>
      <ValueItem xmlns="">41447395</ValueItem>
      <ValueItem xmlns="">56936495</ValueItem>
      <ValueItem xmlns="">70660044</ValueItem>
    </Value>
  </Item>
</NVPList> 



ご覧のとおり、SubscriptionData_AFTER_XML 列の最終的な xml 結果には 2 つの問題があります。

問題1

サブスクリプション ID 6070 の場合、アカウント番号 39448474 が<ValueItem>ノード リストで繰り返されていますが、これは望ましくありません。これを修正するには、xml で現在の AccountNumber 値を照会し、それらの AccountNumbers を以前の値から除外する必要があります。INNER JOIN

SQL クエリ 3:このクエリは、SubscriptionData_XML 列の現在のすべての AccountNumbers を含む結果セットを提供します。これを使用して、 SQL クエリ 1の結果セット
からこれらの AccountNumbers を除外できます。

SELECT SubscriptionID, t.c.value('.', 'varchar(MAX)') as CurrentValueItems
FROM dbo.GoldenEgg 
CROSS APPLY SubscriptionData_XML.nodes('declare default element namespace "http://www.whatevernamspace.com/v1";
                                    /NVPList/Item/Value/ValueItem') as t(c)
WHERE SubscriptionData_XML IS NOT NULL

SQL クエリ 3 の結果:
CurrentValueItems

すべてをまとめて正しい最終結果を得る

SQL クエリ 4:

UPDATE ge
SET SubscriptionData_AFTER_XML.modify
('declare default element namespace "http://www.whatevernamspace.com/v1";
  insert sql:column("t1.AccountNumberXml") as last into (/NVPList/Item/Value)[1]')          
FROM dbo.GoldenEgg ge
INNER JOIN (SELECT 
            ge2.SubscriptionID,
            CAST((SELECT DISTINCT ValueItem = ISNULL(ge1.AccountNumber,'')
                    FROM dbo.GoldenEgg ge1
                    --make sure we are not inserting AccountNumbers that already exists in the subscription data
                    WHERE ge1.AccountNumber NOT IN (SELECT t.c.value('.', 'varchar(MAX)') as CurrentValueItems
                                                    FROM dbo.GoldenEgg 
                                                    CROSS APPLY SubscriptionData_XML.nodes('declare default element namespace "http://www.whatevernamspace.com/v1";
                                                                                     /NVPList/Item/Value/ValueItem') as t(c)
                                                    WHERE SubscriptionData_XML IS NOT NULL
                                                    AND SubscriptionID = ge2.SubscriptionID) 
                    AND ge1.SubscriptionID = ge2.SubscriptionID                     
                    FOR XML PATH('')) AS xml) as AccountNumberXml
            FROM dbo.GoldenEgg ge2
            WHERE ge2.SubscriptionData_AFTER_XML IS NOT NULL) t1 ON t1.SubscriptionID = ge.SubscriptionID
WHERE ge.SubscriptionData_AFTER_XML IS NOT NULL

SQL クエリ 4 XML 結果(SubscriptionID 6070 SubscriptionData_AFTER_XML 列):

ご覧のとおり、AccountNumber 39448474 は xml に 1 回だけリストされています。

<NVPList xmlns="http://www.whatevernamspace.com/v1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <Item>
    <Name>AccountNumbers</Name>
    <Value>
      <ValueItem>39448474</ValueItem>
      <ValueItem xmlns="">41447395</ValueItem>
      <ValueItem xmlns="">56936495</ValueItem>
      <ValueItem xmlns="">70660044</ValueItem>
    </Value>
  </Item>
</NVPList>



問題 2

with AccountNumber ノード リストが挿入されると、空のxmlns=""ネームスペースが挿入されます。これは、空のxmlns=""名前空間を削除するために使用したクエリです。

SQL クエリ 5:

UPDATE dbo.GoldenEgg
SET SubscriptionData_AFTER_XML = CONVERT(XML, REPLACE(CONVERT(NVARCHAR(MAX), SubscriptionData_AFTER_XML), N'xmlns=""',''))
WHERE SubscriptionData_AFTER_XML IS NOT NULL

SQL クエリ 5 XML 結果(SubscriptionID 6070):

<NVPList xmlns="http://www.whatevernamspace.com/v1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <Item>
    <Name>AccountNumbers</Name>
    <Value>
      <ValueItem>39448474</ValueItem>
      <ValueItem>41447395</ValueItem>
      <ValueItem>56936495</ValueItem>
      <ValueItem>70660044</ValueItem>
    </Value>
  </Item>
</NVPList>


これが、似たようなことをする必要がある人に役立つことを願っています

于 2016-11-09T20:46:16.960 に答える