Обновление определенных узлов XML в таблице на основе объединения значений в поле XML с помощью T-SQL - PullRequest
0 голосов
/ 30 апреля 2018

Я должен уделить этой проблеме много времени и поисков. Я даже почти получаю вывод, но проблема в том, что соединение со многими вызывает мою проблему. вот мои данные

--notice some of the Account nodes have elements that others don't
DECLARE @tbl TABLE(ID INT,fkey int, YourXML XML)

INSERT INTO @tbl (id, fkey, YourXML)
    SELECT 
        98, 8,
        N'<Params>
    <Account>
        <FirstName>Michael</FirstName>
        <LastName>Bar</LastName>
        <tcode>8</tcode>
    </Account>
    <Account>
        <FirstName>Pam</FirstName>
        <LastName>Bar</LastName>
    </Account>
</Params>'

    UNION 

    SELECT 
        99, 9, 
        N'<Params>
    <Account>
        <FirstName>Phil</FirstName>
        <LastName>Foo</LastName>
    </Account>
    <Account>
        <FirstName>Rebecca</FirstName>
        <LastName>Foo</LastName>
        <whatever>argh</whatever>
    </Account>
</Params>'

DECLARE @tbl2 TABLE(id INT, fkey INT, sfirst VARCHAR(255), slast VRACHAR(255))

INSERT INTO @tbl2 (id, fkey, sfirst, slast)
    SELECT 1, 8, 'Michael', 'Bar'
    UNION
    SELECT 2, 8, 'Pam', 'Bar'
    UNION
    SELECT 3, 9, 'Phil', 'Foo'
    UNION
    SELECT 4, 9, 'Rebecca', 'Foo'

--expected output

/* expected output
<Params>
    <Account>
        <FirstName>first1</FirstName>
        <LastName>last1</LastName>
        <tcode>8</tcode>
    </Account>
    <Account>
        <FirstName>first2</FirstName>
        <LastName>last2</LastName>
    </Account>
     <Account>
        <FirstName>first3</FirstName>
        <LastName>last3</LastName>
    </Account>
    <Account>
        <FirstName>first4</FirstName>
        <LastName>last4</LastName>
        <whatever>argh</whatever>
    </Account>
</Params>'
*/

Окончательным решением стал код, который выглядел следующим образом, но не содержал переменные теги xml, такие как <tcode>, который был в одной учетной записи, и <whatever>, который был в другой

;WITH cte AS
(
    SELECT 
        YourXML,
        (SELECT DISTICNT
             'first' + REPLACE(STR(se.ID,9),' ','') AS FirstName,
             'last' + REPLACE(STR(se.ID,9),' ','') AS LastName
         FROM 
             @tbl AS sea
         INNER JOIN
             @tbl2 se ON sea.fkey = se.fkey
         CROSS APPLY 
             sea.YourXML.nodes(N'/Params/Account') AS x(nth)
         WHERE 
             sea.id = ilv.id
         FOR XML PATH('Account'), ROOT('Params'), TYPE) AS NewAdditionalInfo
    FROM 
        @tbl AS ilv
)
UPDATE cte 
SET YourXML = NewAdditionalInfo;

Затем я выполнил двойной вложенный цикл while: 1 для идентификатора @tbl и 2 для count() на количестве узлов.

Я заметил, что

update @tbl
set YourXML.modify('replace value of (//Account/FirstName/text())[sql:variable("@tenantcount")][1] with concat(sql:column("sfirst"),sql:column("ValTbl.id") cast as xs:string ?)')
....
where @tbl.id = @current_id

работал, но опять-таки стал бы жертвой проблемы один ко многим

Ответы [ 2 ]

0 голосов
/ 01 мая 2018

спасибо за помощь сообществ

;WITH cte AS
(
    SELECT *
          ,(
                SELECT 
                t.YourXML
                        .query(N'/Params/Account[(FirstName/text())[1]=sql:column("sfirst") 
                                             and (LastName/text())[1]=sql:column("slast")]')
                        .query(N'<Account>
                                 {
                                    for $nd in /Account/*
                                    return 
                                    if(local-name($nd)="FirstName") then
                                        <FirstName>{concat("first"[1],xs:string(sql:column("t2.id")))}</FirstName>
                                    else if(local-name($nd)="LastName") then
                                        <LastName>{concat("last"[1],xs:string(sql:column("t2.id")))}</LastName>
                                    else
                                    $nd
                                 }  
                                 </Account> ') AS [*]
                FROM tbl AS t
                INNER JOIN tbl2 AS t2 ON t.fkey=t2.fkey
                where t.id = tt.id
                ORDER BY t2.id
                FOR XML PATH(''),ROOT('Params'),TYPE
           ) AS NewXML
    FROM tbl AS tt
)
update cte set YourXML = NewXML
select * from tbl
0 голосов
/ 30 апреля 2018

Что по этому поводу:

SELECT t.YourXML
        .query(N'/Params/Account[(FirstName/text())[1]=sql:column("sfirst") 
                             and (LastName/text())[1]=sql:column("slast")]')
        .query(N'<Account>
                 {
                    for $nd in /Account/*
                    return 
                    if(local-name($nd)="FirstName") then
                        <FirstName>{concat($nd/text()[1],xs:string(sql:column("t2.id")))}</FirstName>
                    else if(local-name($nd)="LastName") then
                        <LastName>{concat($nd/text()[1],xs:string(sql:column("t2.id")))}</LastName>
                    else
                    $nd
                 }  
                 </Account> ') AS [*]
FROM @tbl AS t
INNER JOIN @tbl2 AS t2 ON t.fkey=t2.fkey
ORDER BY t2.id
FOR XML PATH(''),ROOT('Params');

Результат

<Params>
  <Account>
    <FirstName>Michael1</FirstName>
    <LastName>Bar1</LastName>
    <tcode>8</tcode>
  </Account>
  <Account>
    <FirstName>Pam2</FirstName>
    <LastName>Bar2</LastName>
  </Account>
  <Account>
    <FirstName>Phil3</FirstName>
    <LastName>Foo3</LastName>
  </Account>
  <Account>
    <FirstName>Rebecca4</FirstName>
    <LastName>Foo4</LastName>
    <whatever>argh</whatever>
  </Account>
</Params>

Некоторое объяснение

XML's .query() позволяет поместить это в серию:

SomeXML.query(N'XQuery').query(N'OtherXQuery')

Первый .query() использует sql:column для фильтрации <Account>, где FirstName и LastName равны sfirst и slast.
Следующий .query() использует запрос FLWOR для обхода всех узлов ниже <Account> и возвращает их в зависимости от их имени.
При этом другие узлы просто проходят через ...

T-SQL XQuery довольно ограничен, вы не можете динамически определять новые элементы или атрибуты, а также не можете создавать структуру вообще, но вы можете сделать довольно много: -D

Это не обновляет исходную таблицу, но возвращает точно ожидаемый результат.

...