Я ищу способ обновить (.modify ('вставить в ..'), чтобы быть конкретным) столбец XML в таблице с фрагментами xml из другой таблицы, связанной внешним ключом.
Например, моя структура таблицы выглядит так (упрощенно):
- Поля с 1 по 5 в каждой таблице можно игнорировать; их единственная цель - объяснить поля Xx.
- Поля Xx в каждой таблице определены как XML и предварительно заполнены фрагментом XML, который содержит поля из таблицы внутри тега, имя таблицы. Фрагменты XML показаны после этого списка.
- Таблица B и таблица C имеют внешний ключ FK_A, который связывает их с таблицей A. Таблицы A - B и таблицы A - C относятся к одному к многим (одна запись в A может иметь несколько записей в B и C).
Теперь к примерным значениям поля 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>
Проблема здесь в том, как мне обновить таблицу A, вставив все XB и XC в качестве первых (или последних) в соответствующий 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>
Что я пробовал на данный момент?
До сих пор я лучше всего руководствовался принципом «разделяй и властвуй» (решение из двух частей, которое не работает).
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;
Это обновляет XML только с первым фрагментом XML из таблиц B и C.
Обновление: всем, кто может столкнуться с этим вопросом, просмотрите ответ @Shnugo вместе с отмеченным ответом. Оба подхода идеальны. Я отметил решение @ gofr1 как ответ просто потому, что он ответил первым. Еще одно соображение для будущих охотников за квестами - нравится ли вам CTE или sub-select (как указал Шнуго).