2016-10-27 7 views
3

別のテーブルのxmlフラグメントを含むテーブルのXML列を更新する方法(.modify( 'insert into ..'))を探しています。外部キーによってリンクされています。別のリンクテーブルからのXMLフラグメントを使用したT-SQL XMLアップデート

例えば、私のテーブル構造は、(簡略化)以下のようになり:各表の1〜5は、無視することができる

Table structure

  1. フィールド。彼らの唯一の目的は にフィールドXxを説明することです。
  2. 各フィールドのXxはXMLとして定義され、タグ内のテーブルのフィールド、テーブル名を含むXMLフラグメントが事前に設定されています。このリストの後にXMLフラグメントが表示されます。
  3. 表Bおよび表Cは、それらを表Aにリンクする外部キーFK_Aを持っています。表A-Bおよび表A-Cは1対多です(Aの1つのレコードはBおよびCに複数のレコードを持つことができます)。
  4. XXフィールドのサンプル値に今

、前に私は達成するために必要なものに:

<!-- Table A record 1 --> 
<TableA PK_A="1"> 
    <A1>Avalue</A1> 
    <A2>Avalue</A2> 
    <A3>Avalue</A3> 
    <A4>Avalue</A4> 
    <A5>Avalue</A5> 
</TableA> 

<!-- Table B record 1 --> 
<TableB PK_B="1" FK_A="1"> 
    <B1>Bvalue1</B1> 
    <B2>Bvalue1</B2> 
    <B3>Bvalue1</B3> 
    <B4>Bvalue1</B4> 
    <B5>Bvalue1</B5> 
</TableB> 
<!-- Table B record 2 --> 
<TableB PK_B="2" FK_A="1"> 
    <B1>Bvalue2</B1> 
    <B2>Bvalue2</B2> 
    <B3>Bvalue2</B3> 
    <B4>Bvalue2</B4> 
    <B5>Bvalue2</B5> 
</TableB> 

<!-- Table C record 1 --> 
<TableC PK_C="1" FK_A="1"> 
    <C1>Cvalue1</C1> 
    <C2>Cvalue1</C2> 
    <C3>Cvalue1</C3> 
    <C4>Cvalue1</C4> 
    <C5>Cvalue1</C5> 
</TableC> 
<!-- Table C record 2 --> 
<TableC PK_C="2" FK_A="1"> 
    <C1>Cvalue2</C1> 
    <C2>Cvalue2</C2> 
    <C3>Cvalue2</C3> 
    <C4>Cvalue2</C4> 
    <C5>Cvalue2</C5> 
</TableC> 

ここでの問題ですが、私は(最初のように、すべてのXBSとXCSを挿入することによって、表Aを更新する方法をまたは最後に)対応するXA?私は、テーブル全体を更新する単一の操作を好む。

操作した後、XAは、次のようになります。私がこれまで試してみました何

<!-- Table A record 1 --> 
<TableA PK_A="1"> 
    <!-- Table B record 1 --> 
    <TableB PK_B="1" FK_A="1"> 
     <B1>Bvalue1</B1> 
     <B2>Bvalue1</B2> 
     <B3>Bvalue1</B3> 
     <B4>Bvalue1</B4> 
     <B5>Bvalue1</B5> 
    </TableB> 
    <!-- Table B record 2 --> 
    <TableB PK_B="2" FK_A="1"> 
     <B1>Bvalue2</B1> 
     <B2>Bvalue2</B2> 
     <B3>Bvalue2</B3> 
     <B4>Bvalue2</B4> 
     <B5>Bvalue2</B5> 
    </TableB> 
    <!-- Table C record 1 --> 
    <TableC PK_C="1" FK_A="1"> 
     <C1>Cvalue1</C1> 
     <C2>Cvalue1</C2> 
     <C3>Cvalue1</C3> 
     <C4>Cvalue1</C4> 
     <C5>Cvalue1</C5> 
    </TableC> 
    <!-- Table C record 2 --> 
    <TableC PK_C="2" FK_A="1"> 
     <C1>Cvalue2</C1> 
     <C2>Cvalue2</C2> 
     <C3>Cvalue2</C3> 
     <C4>Cvalue2</C4> 
     <C5>Cvalue2</C5> 
    </TableC> 
    <A1>Avalue</A1> 
    <A2>Avalue</A2> 
    <A3>Avalue</A3> 
    <A4>Avalue</A4> 
    <A5>Avalue</A5> 
</TableA> 

これまでのところ、私の最大の功績は、分割とルールのアプローチ(2つの部分で解決できない解決法)でした。

WITH CTEB (PK_A, XA, XB) 
AS  (SELECT A.PK_A, 
       a.XA, 
       b.XB 
     FROM TableA AS a 
       INNER JOIN 
       TableB AS b 
       ON b.FK_A = a.PK_A) 
UPDATE CTEB 
    SET XA.modify('insert sql:column("XB") as last into (/TableA)[1]'); 

WITH CTEC (PK_A, XA, XC) 
AS  (SELECT A.PK_A, 
       a.XA, 
       c.XC 
     FROM TableA AS a 
       INNER JOIN 
       TableC AS c 
       ON c.FK_A = a.PK_A) 
UPDATE CTEC 
    SET XA.modify('insert sql:column("XC") as last into (/TableA)[1]'); 

編集:ペーストをコピーするために、任意のテキスト値を与えていないため

謝罪。さあ。

DECLARE @A TABLE (PK_A INT, XA XML); 
DECLARE @B TABLE (PK_B INT, XB XML, FK_A INT); 
DECLARE @C TABLE (PK_C INT, XC XML, FK_A INT); 

INSERT INTO @A 
VALUES (1, '<TableA PK_A="1"><A1>Avalue</A1><A2>Avalue</A2><A3>Avalue</A3><A4>Avalue</A4><A5>Avalue</A5></TableA>') 
INSERT INTO @A 
VALUES (2, '<TableA PK_A="2"><A1>Avalue</A1><A2>Avalue</A2><A3>Avalue</A3><A4>Avalue</A4><A5>Avalue</A5></TableA>') 
INSERT INTO @B 
VALUES (1,'<TableB PK_B="1" FK_A="1"><B1>Bvalue1</B1><B2>Bvalue1</B2><B3>Bvalue1</B3><B4>Bvalue1</B4><B5>Bvalue1</B5></TableB>', 1) 
INSERT INTO @B 
VALUES (2, '<TableB PK_B="2" FK_A="1"><B1>Bvalue2</B1><B2>Bvalue2</B2><B3>Bvalue2</B3><B4>Bvalue2</B4><B5>Bvalue2</B5></TableB>', 1) 
INSERT INTO @B 
VALUES (3, '<TableB PK_B="3" FK_A="2"><B1>Bvalue3</B1><B2>Bvalue3</B2><B3>Bvalue3</B3><B4>Bvalue3</B4><B5>Bvalue3</B5></TableB>', 2) 
INSERT INTO @B 
VALUES (4, '<TableB PK_B="4" FK_A="2"><B1>Bvalue4</B1><B2>Bvalue4</B2><B3>Bvalue4</B3><B4>Bvalue4</B4><B5>Bvalue4</B5></TableB>', 2) 
INSERT INTO @C 
VALUES (1, '<TableC PK_C="1" FK_A="1"><C1>Cvalue1</C1><C2>Cvalue1</C2><C3>Cvalue1</C3><C4>Cvalue1</C4><C5>Cvalue1</C5></TableC>', 1) 
INSERT INTO @C 
VALUES (2, '<TableC PK_C="2" FK_A="1"><C1>Cvalue2</C1><C2>Cvalue2</C2><C3>Cvalue2</C3><C4>Cvalue2</C4><C5>Cvalue2</C5></TableC>', 1) 
INSERT INTO @C 
VALUES (3, '<TableC PK_C="3" FK_A="2"><C1>Cvalue3</C1><C2>Cvalue3</C2><C3>Cvalue3</C3><C4>Cvalue3</C4><C5>Cvalue3</C5></TableC>', 2) 
INSERT INTO @C 
VALUES (4, '<TableC PK_C="4" FK_A="2"><C1>Cvalue4</C1><C2>Cvalue4</C2><C3>Cvalue4</C3><C4>Cvalue4</C4><C5>Cvalue4</C5></TableC>', 2); 

WITH CTEB (PK_A, XA, XB) 
AS  (SELECT A.PK_A, 
       a.XA, 
       b.XB 
     FROM @A AS a, @B as b 
     WHERE b.FK_A = a.PK_A) 
UPDATE CTEB 
    SET XA.modify('insert sql:column("XB") as first into (/TableA)[1]'); 

WITH CTEC (PK_A, XA, XC) 
AS  (SELECT A.PK_A, 
       a.XA, 
       c.XC 
     FROM @A AS a 
       INNER JOIN 
       @C AS c 
       ON c.FK_A = a.PK_A) 
UPDATE CTEC 
    SET XA.modify('insert sql:column("XC") as first into (/TableA)[1]'); 

SELECT * FROM @A; 

これはのみ表B、表Cから最初のXMLフラグメントでXMLを更新

アップデート:この質問に遭遇するかもしれない人にとって、@Shnugoさんをご覧くださいマークされた答えと一緒に答えてください。どちらのアプローチも完璧です。私は答えとして@ gofr1の解決策をマークしました。将来の探求ハンターのためのもう一つの配慮は、あなたがCTEを好むかサブ選択するか(Shnugoが指摘したように)かどうかです。

+1

のようにそれを試してみて、直接XMLフラグメントを追加してください。スクリーンショットを作成して投稿しないでください。人々は、それらのXMLフラグメントを一緒におもちゃにコピー/ペーストしたいと思っています。 GL。 –

+0

ごめんなさい、サンプルのテーブル構造とデータを追加しました。 – Jayachandran

+0

申し訳ありません:)。それはあなたのヒントです。答えに取り組むためにxml-fragmentのサンプルを入力する必要がなければ、人々はもっと助けてくれるでしょう。 –

答えて

3

私はテーブル間に関係がありませんでしたので、私はそれを少しハードコードしました(XMLから取る)。ここでは、テストサンプルで動作するいくつかのソリューション(次回は、実際のデータを貼り付けてください - スクリーンショットではありません)。あなたに似た

テーブルを作成し、挿入するデータ:

USE tempdb 

IF OBJECT_ID(N'#table_a') IS NOT NULL DROP TABLE #table_a 
IF OBJECT_ID(N'#table_b') IS NOT NULL DROP TABLE #table_b 
IF OBJECT_ID(N'#table_c') IS NOT NULL DROP TABLE #table_c 

CREATE TABLE #table_a (
    A nvarchar(2), 
    Xx xml 
) 

CREATE TABLE #table_b (
    B nvarchar(2), 
    Xx xml 
) 

CREATE TABLE #table_c (
    C nvarchar(2), 
    Xx xml 
) 

INSERT INTO #table_a VALUES 
(N'A1', N'<tablea PK_A="1"><A1>Avalue1</A1><A2>Avalue2</A2><A3>Avalue3</A3><A4>Avalue4</A4><A5>Avalue5</A5></tablea>') 

INSERT INTO #table_b VALUES 
(N'B1', N'<tableb PK_B="1" FK_A="1"><B1>Bvalue11</B1><B2>Bvalue12</B2><B3>Bvalue13</B3><B4>Bvalue14</B4><B5>Bvalue15</B5></tableb>'), 
(N'B2', N'<tableb PK_B="2" FK_A="1"><B1>Bvalue21</B1><B2>Bvalue22</B2><B3>Bvalue23</B3><B4>Bvalue24</B4><B5>Bvalue25</B5></tableb>') 

INSERT INTO #table_c VALUES 
(N'C1', N'<tablec PK_C="1" FK_A="1"><C1>Cvalue11</C1><C2>Cvalue12</C2><C3>Cvalue13</C3><C4>Cvalue14</C4><C5>Cvalue15</C5></tablec>'), 
(N'C2', N'<tablec PK_C="2" FK_A="1"><C1>Cvalue21</C1><C2>Cvalue22</C2><C3>Cvalue23</C3><C4>Cvalue24</C4><C5>Cvalue25</C5></tablec>') 

更新:

UPDATE a 
set Xx.modify('insert sql:column("b.Xx") as first into (/tablea)[1]') 
FROM #table_a a 
OUTER APPLY (SELECT (
    SELECT Xx 
    FROM #table_b 
    WHERE a.Xx.value('(/tablea/@PK_A)[1]','int') = Xx.value('(/tableb/@FK_A)[1]','int') 
    FOR XML PATH(''), TYPE).query('/Xx/tableb') as Xx 
    ) b 

UPDATE a 
set Xx.modify('insert sql:column("c.Xx") as first into (/tablea)[1]') 
FROM #table_a a 
OUTER APPLY (SELECT (
    SELECT Xx 
    FROM #table_c 
    WHERE a.Xx.value('(/tablea/@PK_A)[1]','int') = Xx.value('(/tablec/@FK_A)[1]','int') 
    FOR XML PATH(''), TYPE).query('/Xx/tablec') as Xx 
    ) c 

SELECT * 
FROM #table_a 

そして出力:

<tablea PK_A="1"> 
    <tablec PK_C="1" FK_A="1"> 
    <C1>Cvalue11</C1> 
    <C2>Cvalue12</C2> 
    <C3>Cvalue13</C3> 
    <C4>Cvalue14</C4> 
    <C5>Cvalue15</C5> 
    </tablec> 
    <tablec PK_C="2" FK_A="1"> 
    <C1>Cvalue21</C1> 
    <C2>Cvalue22</C2> 
    <C3>Cvalue23</C3> 
    <C4>Cvalue24</C4> 
    <C5>Cvalue25</C5> 
    </tablec> 
    <tableb PK_B="1" FK_A="1"> 
    <B1>Bvalue11</B1> 
    <B2>Bvalue12</B2> 
    <B3>Bvalue13</B3> 
    <B4>Bvalue14</B4> 
    <B5>Bvalue15</B5> 
    </tableb> 
    <tableb PK_B="2" FK_A="1"> 
    <B1>Bvalue21</B1> 
    <B2>Bvalue22</B2> 
    <B3>Bvalue23</B3> 
    <B4>Bvalue24</B4> 
    <B5>Bvalue25</B5> 
    </tableb> 
    <A1>Avalue1</A1> 
    <A2>Avalue2</A2> 
    <A3>Avalue3</A3> 
    <A4>Avalue4</A4> 
    <A5>Avalue5</A5> 
</tablea> 

EDIT

一方の部分のUPDATE:

UPDATE a 
set Xx.modify('insert sql:column("b.Xx") as first into (/tablea)[1]') 
FROM #table_a a 
OUTER APPLY (SELECT (
    SELECT * 
    FROM (
      SELECT Xx 
      FROM #table_b b 
      WHERE a.Xx.value('(/tablea/@PK_A)[1]','int') = b.Xx.value('(/tableb/@FK_A)[1]','int') 
      UNION ALL 
      SELECT Xx 
      FROM #table_c c 
      WHERE a.Xx.value('(/tablea/@PK_A)[1]','int') = c.Xx.value('(/tablec/@FK_A)[1]','int') 
     ) d 
    FOR XML PATH(''), TYPE).query('/Xx/*') as Xx 
    ) b 
+0

この解決策が働くので、プラス投票。しかし、これもやはり2つの部分からなる解決策です。それで、他のソリューションがどのように動くのかを見るのを待つことになります。どうもありがとう。少なくとも私は転倒している。そしてその華麗な。 – Jayachandran

+0

ありがとう!私は1つの部分の更新ソリューションを追加します – gofr1

+0

そして私の喜びを助ける! ;) – gofr1

3

XML-DML文で.modify()は、一度に1つの変更を可能にします。 2つのフラグメントをtbl AのXMLに挿入したい場合、はテーブル全体を更新する単一の操作を好むので、最初に結合された値を準備し、これを1回の呼び出しで挿入することをお勧めします。次のコードは完全にアドホックです...

将来的にはこの

WITH FragmentsToAdd AS 
(
    SELECT tblA.PK_A 
      ,(
      SELECT * 
      FROM 
      (
       SELECT tblB.XB AS [node()] 
       FROM @B AS tblB 
       WHERE tblB.FK_A=tblA.PK_A 
       UNION ALL 
       SELECT tblC.XC AS [node()] 
       FROM @C AS tblC 
       WHERE tblC.FK_A=tblA.PK_A 
      ) AS x 
      FOR XML PATH(''),TYPE 
      ) Fragment 
    FROM @A AS tblA 
    GROUP BY tblA.PK_A 
) 
UPDATE @A SET XA.modify('insert sql:column("Fragment") as first into /TableA[1]') 
FROM @A AS a 
INNER JOIN FragmentsToAdd AS fr ON a.PK_A=fr.PK_A; 

SELECT * FROM @A 
+0

本当の問題では、20以上のテーブルがメインテーブルにリンクされていて、複数のメインテーブルがあるため、このソリューションが大好きです。これにより、メインテーブルごとに1つのクエリ(すぐにストアドプロシージャになる)を持たせることができます。そして将来、UNION ALLでテーブルを追加し続けることで、拡大を続けることができます。答えとしてマーキングする前にもう少し時間をおいてください。 – Jayachandran

関連する問題