Решение T-SQL 2014 XQuery для использования подстроки - PullRequest
0 голосов
/ 26 апреля 2018

Я пытаюсь записать оператор обновления в столбец XML в таблице, отформатированной следующим образом.

это поле поля таблицы

 <Params>
        <Account>
            <FirstName>Michael</FirstName>
            <LastName>Bar</LastName>
        </Account>
        <Account>
            <FirstName>Pam</FirstName>
            <LastName>Foo</LastName>
        </Account>
    </Params>




**this is in on field of ONE of another record in that table
    <Params>
        <Account>
            <FirstName>Darold</FirstName>
            <LastName>ok</LastName>
        </Account>
        <Account>
            <FirstName>Fred</FirstName>
            <LastName>whatever</LastName>
        </Account>
        <Account>
             <FirstName>amy</FirstName>
             <LastName>whatever</LastName>
    </Account>
    </Params>
**

Требуетсяoutput

    <Params>
        <Account>
            <FirstName>Michael2334</FirstName>
            <LastName>Bar2334</LastName>
        </Account>
        <Account>
            <FirstName>Pam2334</FirstName>
            <LastName>Foo2334</LastName>
        </Account>
    </Params>





    <Params>
        <Account>
            <FirstName>Darold2335</FirstName>
            <LastName>ok2335</LastName>
        </Account>
        <Account>
            <FirstName>Fred2335</FirstName>
            <LastName>whatever2335</LastName>
        </Account>
        <Account>
            <FirstName>amy2335</FirstName>
            <LastName>whatever2335</LastName>
        </Account>
    </Params>

Моя конечная цель - обновить xml-поле всей таблицы, содержащее n-е количество узлов со столбцом идентификатора объединенной таблицы, и добавить этот идентификатор к имени и фамилии

«спецификации» должны обновить имя и поставить столбец id (целое число) в конце фамилии и имени (что я решил в PoC из SQLFiddle ниже, но не полностью, поскольку это работает только еслив таблице есть одна запись, и на данный момент используется только первое имя)

Я потратил весь день

Я просмотрел Интернет и изменил функцию (заменил значение)из ...) может влиять только на одну из учетных записей одновременно.Из-за этого мне пришлось создать такой цикл.Но его очень уродливая и нижняя переменная KeepGoing работала бы намного лучше, если бы SQL Server поддерживал функцию XPath matches() и мог проверять наличие цифры с регулярными выражениями , но это не в SQLServer 2017. Мой обходной путь будет использовать contains() 10 раз!Чтобы узнать, готов ли я и могу перейти к следующей записи.

Если у кого-нибудь есть более элегантное решение, пожалуйста, дайте мне знать.Человек, который запрашивает это, хочет, чтобы все это было одним утверждением, а не курсорами.Который я уже из приведенного ниже кода, конечно, пошел и сдался.

1) Какой запрос можно вернуть из приведенного ниже XML, который будет возвращать

4
4

4 дляпоследний символ в FirstName

и

4 для последнего символа в FirstName во втором узле

этот выбор также должен возвращать

5

5

для следующей записи

Но это не ГЛАВНАЯ проблема, это фу, пытающаяся использовать подстроку, и в xpath

я пытаюсьоценивать через цикл while, чтобы я знал, когда прекратить выполнение на 1 , выполнив поиск целого числа в последнем символе, я не смог написать ниже

SELECT XMLCol.value ('// Account / FirstName / text () [substring (., String-length (x) -1,11)] ',' nvarchar (255)) FROM XMLtbl

Я пробовал все варианты только нижечтобы получить такие сообщения, как ...

Сообщение 2203, Уровень 16, Состояние 1, Строка 114
XQuery [XMLtbl.XMLCol.value ()]: только выражения 'http://www.w3.org/2001/XMLSchema#decimal?',' http://www.w3.org/2001/XMLSchema#boolean?' или 'node () *' разрешены как предикаты, найдено 'xs: string'

Здесь есть всеЯ работаю над

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

http://sqlfiddle.com/#!18/7eed1

Сильно благодарен, я знал, что xquery / xpath был нелегким делом, и держался подальше от него и оставил его для экспертов

Последняя скрипка (основано на ответе ниже, но в нем есть еще несколько полейчто я использую, которые не имеют отношения к вопросу)

http://sqlfiddle.com/#!18/afff6

1 Ответ

0 голосов
/ 26 апреля 2018

Ваш вопрос довольно длинный, почти TL; DR , но все еще не очень ясный ... Это поможет обеспечить ожидаемый результат ...

Некоторые предположения и утверждения:

  • Да, .modify() допускает одно единственное изменение на вызов - вполне ограничение ...
  • Вы хотите обновить XML в нескольких местах
  • Сваши спецификации вы хотите добавить идентификатор в XML
  • Не знаю, чего вы хотите достичь с помощью последней буквы

Однако, в вашем случае, кажется, лучше уничтожить XML и воссоздать его с нуля.Для этого вы можете использовать любую функциональность T-SQL:

DECLARE @tbl TABLE(ID INT IDENTITY, YourXML XML);
INSERT INTO @tbl VALUES
(N'<Params>
    <Account>
        <FirstName>Michael</FirstName>
        <LastName>Bar</LastName>
    </Account>
    <Account>
        <FirstName>Pam</FirstName>
        <LastName>Foo</LastName>
    </Account>
</Params>')
,(N'<Params>
    <Account>
        <FirstName>John</FirstName>
        <LastName>Wood</LastName>
    </Account>
    <Account>
        <FirstName>Jane</FirstName>
        <LastName>Smith</LastName>
    </Account>
    <Account>
        <FirstName>Jim</FirstName>
        <LastName>Stone</LastName>
    </Account>
</Params>');

- В запросе используется «обновляемый CTE» для создания значения, которое впоследствии можно будет использовать в UPDATE.

WITH cte AS
(
    SELECT t.YourXML
          ,(
            SELECT 
                  --just silly, to show how it works: append "blah" to the first name
                   Acc.value(N'(FirstName/text())[1]',N'nvarchar(max)') + '_blah' AS FirstName
                   --Just pick the last character as LastName
                  ,RIGHT(Acc.value(N'(LastName/text())[1]',N'nvarchar(max)'),1) AS LastName
                  --Add the ID in the last place
                  ,t2.ID
            FROM @tbl AS t2
            CROSS APPLY t2.YourXML.nodes(N'/Params/Account') AS A(Acc)
            WHERE t2.ID=t.ID
            FOR XML PATH('Account'),ROOT('Params'),TYPE
           ) AS NewXML
    FROM @tbl AS t
)
UPDATE cte SET YourXML=NewXML;

SELECT * FROM @tbl;

Один из этих XML-файлов будет выглядеть после действия

<Params>
  <Account>
    <FirstName>Michael_blah</FirstName>
    <LastName>r</LastName>
    <ID>1</ID>
  </Account>
  <Account>
    <FirstName>Pam_blah</FirstName>
    <LastName>o</LastName>
    <ID>1</ID>
  </Account>
</Params>

ОБНОВЛЕНИЕ

Этот запрос добавит идентификатор строки (с добавлением пятизначного числа).номер) в обе части имени:

WITH cte AS
(
    SELECT t.YourXML
          ,(
            SELECT 
                   Acc.value(N'(FirstName/text())[1]',N'nvarchar(max)') + REPLACE(STR(t2.ID,5),' ','0') AS FirstName
                  ,Acc.value(N'(LastName/text())[1]',N'nvarchar(max)') + REPLACE(STR(t2.ID,5),' ','0') AS LastName
            FROM @tbl AS t2
            CROSS APPLY t2.YourXML.nodes(N'/Params/Account') AS A(Acc)
            WHERE t2.ID=t.ID
            FOR XML PATH('Account'),ROOT('Params'),TYPE
           ) AS NewXML
    FROM @tbl AS t
)
UPDATE cte SET YourXML=NewXML;

SELECT * FROM @tbl;

И этот запрос доставит последний символ каждого имени

SELECT Acc.value(N'substring((FirstName/text())[1],string-length((FirstName/text())[1]),1)',N'char(1)')
FROM @tbl AS t
CROSS APPLY t.YourXML.nodes(N'/Params/Account') AS A(Acc);
...