Використовуйте оператор LIKE у типі даних XML SQL Server


88

Якщо у вас є поле varchar, ви можете легко SELECT * FROM TABLE WHERE ColumnA LIKE '%Test%'перевірити, чи містить цей стовпець певний рядок.

Як це зробити для типу XML?

У мене є таке, що повертає лише рядки, які мають вузол "Текст", але мені потрібно шукати всередині цього вузла

select * from WebPageContent where data.exist('/PageContent/Text') = 1

Відповіді:


70

Ви можете зробити це досить легко:

SELECT * 
FROM WebPageContent 
WHERE data.value('(/PageContent/Text)[1]', 'varchar(100)') LIKE 'XYZ%'

.valueМетод дає фактичне значення, і ви можете визначити , що повинно бути повернуто як VARCHAR (), який ви можете перевірити за заявою LIKE.

Зауважте, це не буде дуже швидко. Отже, якщо у вашому XML є певні поля, які вам потрібно багато перевірити, ви можете:

  • створити збережену функцію, яка отримує XML і повертає значення, яке ви шукаєте, як VARCHAR ()
  • визначте нове обчислюване поле у ​​вашій таблиці, яке викликає цю функцію, і зробіть його стовпцем PERSISTED

За допомогою цього ви в основному "витягнули б" певну частину XML в обчислюване поле, зробили його збереженим, а потім ви могли б дуже ефективно шукати в ньому (чорт візьміть: ви навіть можете ІНДЕКСУВАТИ це поле!).

Марк


1
В основному я реалізую функцію пошуку, тому хочу шукати XML-стовпець лише на вузлах "Текст", а потім повертати підрядок, щоб вказати, що пошук знайшов відповідність. Наприклад, пошук за "привіт там", а не повернення цілого стовпця xml, я б просто повернув такий підрядок, як "хлопець сказав привіт там і переніс ..."
Джон

1
Побийте мене за 5 секунд. Інша можливість - розглянути можливість використання вільного тексту, якщо ваші дані
доступні

10
для пошуку в цілому поданому: ДЕ xmlField.value ('.', 'varchar (max)') ПОДОБНО '% FOO%'
jhilden

стежте за набридливими просторами імен Xml, якщо повернете
НУЛЬ

87

Ще один варіант - передати XML як nvarchar, а потім шукати заданий рядок так, ніби XML є полем nvarchar.

SELECT * 
FROM Table
WHERE CAST(Column as nvarchar(max)) LIKE '%TEST%'

Мені подобається це рішення, оскільки воно чисте, легко запам’ятовується, важко зіпсувати і може використовуватися як частина речення where.

РЕДАГУВАТИ: Як Кліфф згадує про це, ви можете використовувати:

... nvarchar, якщо є символи, які не перетворюються у varchar


3
Так само, або nvarchar, якщо є символи, які не перетворюються на varchar ВИБРАТИ * З ТАБЛИЦИ, ДЕ АКСТ (стовпець як nvarchar (макс.)) ЯК "% TEST%"
Кліф Коултер

[Помилка] 42000 - [SQL Server] Перетворення одного або декількох символів із XML у цільове сортування неможливе
digz6666

[Помилка] 22018 - [SQL Server] Явне перетворення з типу даних xml в текст не допускається.
digz6666

Звучить, ти робиш щось не так @ digz6666
Squazz

1
@Squazz Ви востаннє проголосували за цю відповідь учора. Тепер ваш голос заблоковано, якщо цю відповідь не відредаговано. :)
digz6666

10

Іншим варіантом є пошук XML як рядка, перетворивши його на рядок, а потім використовуючи LIKE. Однак, оскільки обчислюваний стовпець не може бути частиною речення WHERE, вам потрібно обернути його в інший SELECT, наприклад:

SELECT * FROM
    (SELECT *, CONVERT(varchar(MAX), [COLUMNA]) as [XMLDataString] FROM TABLE) x
WHERE [XMLDataString] like '%Test%'

Зауважте, це може обходити будь-які селективні xml-індекси, які у вас є, і впливати на продуктивність.
Rudy Hinojosa

0

Це те, що я збираюся використовувати на основі відповіді marc_s:

SELECT 
SUBSTRING(DATA.value('(/PAGECONTENT/TEXT)[1]', 'VARCHAR(100)'),PATINDEX('%NORTH%',DATA.value('(/PAGECONTENT/TEXT)[1]', 'VARCHAR(100)')) - 20,999)

FROM WEBPAGECONTENT 
WHERE COALESCE(PATINDEX('%NORTH%',DATA.value('(/PAGECONTENT/TEXT)[1]', 'VARCHAR(100)')),0) > 0

Повернути підрядок пошуку, де існують критерії пошуку


Чи потрібні параметри, щоб якось запобігти впорскуванню?
Джон

2
УВАЖАЙТЕ: ці функції XML чутливі до регістру - DATA.VALUE не працюватиме! Це має бути .value (...)
marc_s 02
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.