Как фильтровать строки на основе значения XML имени атрибута в SQL - PullRequest
0 голосов
/ 02 апреля 2020

У меня есть таблица Web.Log со столбцом Properties, которая содержит следующее содержимое

<properties>
  ...
  <property key="ActivityId" />
  <property key="UserName">John Doe</property>
</properties>

Как отфильтровать Web.Log таблицу только по строкам, которая содержит John Doe свойство userName?

Теперь я использую

select * from Web.Log
where cast(Properties as nvarchar(max)) 
like '%<property key="UserName">John Doe</property>%'

, что похоже на обходной путь: -)

Ответы [ 2 ]

2 голосов
/ 03 апреля 2020

Должно быть быстрее использовать собственный XML метод .exist().

Сначала создайте сценарий макета для имитации вашей проблемы:

DECLARE @tbl TABLE(ID INT IDENTITY, SomeText VARCHAR(100),Properties XML);
INSERT INTO @tbl VALUES('John Doe exists'
                       ,'<properties>
                            <property key="ActivityId" />
                            <property key="UserName">John Doe</property>
                         </properties>')
                        ,('John Doe doesn''t exist'
                       ,'<properties>
                            <property key="ActivityId" />
                            <property key="UserName">Someone else</property>
                         </properties>')
                        ,('John Doe exists'
                       ,'<properties>
                            <property key="ActivityId" />
                            <property key="UserName">John Doe</property>
                         </properties>');

- Мы можем использовать переменные для общей фильтрации

DECLARE @SearchFor VARCHAR(100)='UserName';
DECLARE @FindThis  VARCHAR(100)='John Doe';

- Это запрос:

SELECT *
FROM @tbl t 
WHERE t.Properties.exist('/properties/property[@key=sql:variable("@SearchFor") and text()[1]=sql:variable("@FindThis")]')=1;

Идея вкратце:

  • Мы можем используйте .exist() непосредственно в предложении WHERE.
  • Значение WHERE TRUE, если в заданном XPath имеется хотя бы одно попадание
  • =1 можно установить на =0 в порядок возврата отрицательного набора
  • XPath использует предикат XQuery для поиска <property> с заданным ключом и значением.
0 голосов
/ 02 апреля 2020

Используйте XQUERY и EXISTS:

SELECT {Columns}
FROM Web.Log L
WHERE EXISTS (SELECT 1
              FROM L.[Properties].nodes('/properties/property')p(p)
              WHERE p.p.value('(text())[1]','nvarchar(50)') = 'John Doe')
...