SQL Xml для запроса Xpath - PullRequest
2 голосов
/ 20 мая 2019

Попытка вернуть значение поля XML через запрос Xpath.

Вот как выглядит XML в моментальном снимке.

<?xml version="1.0" encoding="utf-16"?>  
<ArrayOfCustomProperty xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">    
<CustomProperty>      
    <DeveloperId>Test123</DeveloperId>      
    <Key>AgreedToTerms</Key>      
    <Value>True</Value>    
</CustomProperty>    
<CustomProperty>      
    <DeveloperId>Test456</DeveloperId>      
    <Key>ValidForLoyaltyPoints</Key>      
    <Value>False</Value>    
</CustomProperty>  
</ArrayOfCustomProperty>

(извините за плохо отформатированный XML ... У StackOverflows RCE возникают проблемы с его рендерингом. В конце ArrayOfCustomProperty закрывается, но по какой-то причине просто не отображается)

Этот запрос работает для меня ....

  SET @return = CAST(CAST(@xmlData AS xml).query('ArrayOfCustomProperty/CustomProperty/Key[text()=sql:variable("@key")]/../Value/text()') AS nvarchar(255))

Это позволяет мне иметь функцию, в которой параметрами являются @xmlData и @key для того, что нужно искать. Мне нужна другая функция (или может изменить эту), где я также могу искать узел [DeveloperId], поэтому третий параметр будет передан как @devId. Я пробовал довольно много разных вещей, но пока у меня ничего не получалось. Я хотел бы запрос, где я могу получить [Значение], когда [DeveloperId] и [Ключ] присутствуют, используя ту же структуру (если возможно), как работает текущий запрос Xpath.

Заранее спасибо за любую помощь.

Ответы [ 3 ]

1 голос
/ 27 мая 2019

Вы должны попытаться вернуть как можно меньше из XML.
Лучше всего было уменьшить количество разбора двигателя до необходимого минимума.
И вам следует избегать обратной навигации, используя ../. Это хорошо известный убийца производительности.

Попробуйте это:

DECLARE @tbl TABLE(YourXml XML);
INSERT INTO @tbl VALUES
(N'<?xml version="1.0" encoding="utf-16"?>  
<ArrayOfCustomProperty xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">    
<CustomProperty>      
    <DeveloperId>Test123</DeveloperId>      
    <Key>AgreedToTerms</Key>      
    <Value>True</Value>    
</CustomProperty>    
<CustomProperty>      
    <DeveloperId>Test456</DeveloperId>      
    <Key>ValidForLoyaltyPoints</Key>      
    <Value>False</Value>    
</CustomProperty>  
</ArrayOfCustomProperty>');

- Ваш ключ-переменная

DECLARE @key VARCHAR(100)='ValidForLoyaltyPoints' ;

- Запрос

SELECT cp.value('(DeveloperId/text())[1]','nvarchar(250)') AS DeveloperId
      ,cp.value('(Value/text())[1]','nvarchar(250)') AS Value
FROM @tbl t
CROSS APPLY t.YourXml.nodes('/ArrayOfCustomProperty/CustomProperty[(Key/text())[1]=sql:variable("@key")]') A(cp);

XPath/XQuery в .nodes() опустится до <CustomProperty> и вернет его с <Key>, где текст ключа подобен данному фильтру. Найденный <CustomProperty> возвращается. Используя .value(), мы можем прочитать элементы ниже данного свойства.

UPDATE

Выглядит так, как будто вы пытаетесь получить <Value> как скалярное значение в зависимости от <DeveloperId> и <Key>. Вы можете использовать простой предикат для одновременного запроса:

DECLARE @key VARCHAR(100)='ValidForLoyaltyPoints' ;
DECLARE @devId VARCHAR(100)='Test456';
--the Query

SELECT t.YourXml.value(N'(/ArrayOfCustomProperty
                          /CustomProperty[(DeveloperId/text())[1]=sql:variable("@devId") 
                                      and (Key/text())[1]=sql:variable("@key")]
                          /Value/text())[1]',N'nvarchar(100)')
FROM @tbl t;

Вы читаете это как

  • Погружение в массив
  • Погрузитесь глубже в CustomProperty
  • Найти элемент, где фильтр соответствует ...
  • ... и вернуть его значение
1 голос
/ 20 мая 2019

Вы можете преобразовать xml данные в таблицу, а затем обработать таблицу.Как то так.

declare @xml xml=N'<?xml version="1.0" encoding="utf-16"?>  
<ArrayOfCustomProperty xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">    
<CustomProperty>      
    <DeveloperId>Test123</DeveloperId>      
    <Key>AgreedToTerms</Key>      
    <Value>True</Value>    
</CustomProperty>    
<CustomProperty>      
    <DeveloperId>Test456</DeveloperId>      
    <Key>ValidForLoyaltyPoints</Key>      
    <Value>False</Value>    
</CustomProperty>  
</ArrayOfCustomProperty>',
@key varchar(50)

;with cte as (
select t.v.value('DeveloperId[1]','varchar(50)') DeveloperId,
    t.v.value('Key[1]','varchar(50)') [Key],
    t.v.value('Value[1]','varchar(50)') [Value]
from @xml.nodes('ArrayOfCustomProperty/CustomProperty') t(v)
)
select * from cte
where [Key] = @key
0 голосов
/ 30 мая 2019

@ Shnugo

Это то, что вы имели в виду с вашим последним комментарием?

DECLARE @tbl TABLE(YourXml XML);
INSERT INTO @tbl VALUES (@xmlData)

SELECT t.YourXml.value('(/ArrayOfCustomProperty/CustomProperty/Value/text())[1]','nvarchar(250)') AS Value 
FROM @tbl t
WHERE t.YourXml.value('(/ArrayOfCustomProperty/CustomProperty/Key/text())[1]','nvarchar(250)') = @key 
AND
t.YourXml.value('(/ArrayOfCustomProperty/CustomProperty/DeveloperId/text())[1]','nvarchar(250)') = @devId
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...