Як я можу запитати значення в стовпці XML SQL Server


127

У мене є наступний XML, що зберігається у стовпці XML (називається Roles) у базі даних SQL Server.

<root>
   <role>Alpha</role>
   <role>Beta</role>
   <role>Gamma</role>
</root>

Я хотів би перерахувати всі рядки, які в них відіграють певну роль. Ця роль передана параметром.

Відповіді:


198
select
  Roles
from
  MyTable
where
  Roles.value('(/root/role)[1]', 'varchar(max)') like 'StringToSearchFor'

На цих сторінках ви дізнаєтесь більше про те, як запросити XML у T-SQL:

Запит на XML-поля за допомогою t-sql

Вирівнювання XML-даних у SQL Server

EDIT

Погравши з ним трохи більше, я закінчив цей дивовижний запит, який використовує CROSS APPLY . Цей пошук буде шукати в кожному рядку (ролі) значення, яке ви вводите як вираз ...

Враховуючи цю структуру таблиці:

create table MyTable (Roles XML)

insert into MyTable values
('<root>
   <role>Alpha</role>
   <role>Gamma</role>
   <role>Beta</role>
</root>')

Ми можемо запитувати так:

select * from 

(select 
       pref.value('(text())[1]', 'varchar(32)') as RoleName
from 
       MyTable CROSS APPLY

       Roles.nodes('/root/role') AS Roles(pref)
)  as Result

where RoleName like '%ga%'

Ви можете перевірити скрипт SQL тут: http://sqlfiddle.com/#!18/dc4d2/1/0


5
Він відповідає на все моє запитання, що робить [1]ваша відповідь?
Бістро

1
Чудова відповідь, я голосую за це, але рядок повинен бути варчар Я думаю
AaA

7
@Bistro Питання про це [1]було справді хорошим питанням. Це означає, що ви вибираєте перше значення ролі з XML, і це означає, що це буде працювати тільки для пошуку Alphaу вашому зразку xml. Він не знайде рядок, якщо ви шукаєте Beta.
Мікаель Ерікссон

1
У моєму випадку мені довелося запитувати вузли з конкретним значенням атрибута. Ця відповідь послужила моїм рішенням. Мені просто довелося ставити подвійні лапки навколо значення атрибута.
Джон Н

Якщо XML має простір імен, як ми запитуємо його?
FMFF

36
declare @T table(Roles xml)

insert into @T values
('<root>
   <role>Alpha</role>
   <role>Beta</role>
   <role>Gamma</role>
</root>')

declare @Role varchar(10)

set @Role = 'Beta'

select Roles
from @T
where Roles.exist('/root/role/text()[. = sql:variable("@Role")]') = 1

Якщо ви хочете, щоб запит працював так, як where col like '%Beta%'ви можете використовуватиcontains

declare @T table(Roles xml)

insert into @T values
('<root>
   <role>Alpha</role>
   <role>Beta</role>
   <role>Gamma</role>
</root>')

declare @Role varchar(10)

set @Role = 'et'

select Roles
from @T
where Roles.exist('/root/role/text()[contains(., sql:variable("@Role"))]') = 1

13

якщо назва вашого поля - Ролі, а назва таблиці - таблиця1, ви можете скористатися наступним для пошуку

DECLARE @Role varchar(50);
SELECT * FROM table1
WHERE Roles.exist ('/root/role = sql:variable("@Role")') = 1

це добре, чи є тут спосіб пошуку за допомогою like? forexample /root/role like ....
Бістро

2
використовувати .value('(/root/role)[1]', 'varchar(max)') like '%yourtext%'замість того, existsяк пояснив
Леніел

4
Ви пробували це? Він знаходить все, незалежно від того, що ви вкладаєте @Role.
Мікаел Ерікссон

6

Я придумав просту роботу, під якою теж легко запам'ятатись :-)

select * from  
(select cast (xmlCol as varchar(max)) texty
 from myTable (NOLOCK) 
) a 
where texty like '%MySearchText%'

1
Ми не повинні здійснювати пошук за допомогою строкових маніпуляцій, оскільки це призведе до занадто повільних пошуків
Малькольм Сальвадор

5

Ви можете зробити наступне

declare @role varchar(100) = 'Alpha'
select * from xmltable where convert(varchar(max),xmlfield) like '%<role>'+@role+'</role>%'

Очевидно, це трохи хак, і я не рекомендував би його для будь-яких формальних рішень. Однак я вважаю цю методику дуже корисною для виконання запитів adhoc на стовпцях XML в SQL Server Management Studio для SQL Server 2012.


2

Корисна порада. Запит на значення у стовпці XML SQL Server (XML з простором імен)

напр

Table [dbo].[Log_XML] contains columns Parametrs (xml),TimeEdit (datetime)

наприклад, XML у параметрах:

<ns0:Record xmlns:ns0="http://Integration"> 
<MATERIAL>10</MATERIAL> 
<BATCH>A1</BATCH> 
</ns0:Record>

наприклад Запит:

select
 Parametrs,TimeEdit
from
 [dbo].[Log_XML]
where
 Parametrs.value('(//*:Record/BATCH)[1]', 'varchar(max)') like '%A1%'
 ORDER BY TimeEdit DESC

1

Нижче я використовував оператор для отримання значень у XML у таблиці Sql

with xmlnamespaces(default 'http://test.com/2008/06/23/HL.OnlineContract.ValueObjects')
select * from (
select
            OnlineContractID,
            DistributorID,
            SponsorID,
    [RequestXML].value(N'/OnlineContractDS[1]/Properties[1]/Name[1]', 'nvarchar(30)') as [Name]
   ,[RequestXML].value(N'/OnlineContractDS[1]/Properties[1]/Value[1]', 'nvarchar(30)') as [Value]
     ,[RequestXML].value(N'/OnlineContractDS[1]/Locale[1]', 'nvarchar(30)') as [Locale]
from [OnlineContract]) as olc
where olc.Name like '%EMAIL%' and olc.Value like '%EMAIL%' and olc.Locale='UK EN'

Що робити, якщо XML не містить визначення простору імен?
Муфлікс

0

Ви можете запитувати весь тег або лише конкретне значення. Тут я використовую підстановку для просторів імен xml.

declare @myDoc xml
set @myDoc = 
'<Root xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://stackoverflow.com">
    <Child>my value</Child>
 </Root>'

select @myDoc.query('/*:Root/*:Child') -- whole tag
select @myDoc.value('(/*:Root/*:Child)[1]', 'varchar(255)') -- only value
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.