Где предложение IN, когда столбец является типом данных XML - PullRequest
0 голосов
/ 03 октября 2019
<users>
    <user key="location" value="123" />
</users>

Как я могу выполнить запрос типа WHERE IN (123,456,789), если значение представляет собой столбец XML?

Пока мой запрос находится ниже:

select *
from users
where meta.exist('//user[./@key="location" and ./@value="123"]') = 1

Ответы [ 2 ]

3 голосов
/ 03 октября 2019

Есть много способов сделать это. Вот самый простой.

-- Sample data
DECLARE @users TABLE (userId INT IDENTITY, meta XML)
INSERT @users(meta) VALUES 
('<users><user key="location" value="000" /></users>'),
('<users><user key="location" value="123" /></users>'),
('<users><user key="location" value="456" /></users>'),
('<users><user key="location" value="789" /></users>'),
('<users><user key="location" value="999" /></users>');

-- Solution
SELECT      u.userId, uv.val
FROM        @users AS u
CROSS APPLY (
            VALUES(meta.value('(//user/@value)[1]', 'int'),
                meta.value('(//user/@key)[1]', 'VARCHAR(8)'))
        ) AS uv(val,[key])
 WHERE  uv.val IN (123,456,789) and uv.[key]='location'

Возвращает:

userId      val
----------- -----------
2           123
3           456
4           789
2 голосов
/ 04 октября 2019

Как показывают решения Alan, одним из способов является чтение всего набора и использование внешнего WHERE для фильтрации этого. Это работает и может быть лучшим подходом. Но с большими XML-файлами .exist() намного быстрее, потому что уничтожение прекращается после первого попадания.

В качестве альтернативы вы можете попробовать это:

Кредиты Алану Бурштейну для MCVE

-- Sample data
DECLARE @users TABLE (userId INT IDENTITY, meta XML)
INSERT @users(meta) VALUES 
('<users><user key="location" value="000" /></users>'),
('<users><user key="location" value="123" /></users>'),
('<users><user key="location" value="456" /></users>'),
('<users><user key="location" value="789" /></users>'),
('<users><user key="location" value="999" /></users>');

- Я обрамляю список номеров запятыми

DECLARE @SearchFor VARCHAR(100)=',123,456,789,';

- Простой contains() ищет ,123, найдет строку

SELECT *
FROM @users
WHERE meta.exist('/users/user[@key="location" and contains(sql:variable("@SearchFor"),concat(",",@value,","))]')=1;

Мы можемиспользуйте sql:variable(), чтобы ввести внешнюю переменную в XQuery. (Вы можете сделать то же самое с "location" , конечно ...)

Если ваш список чисел взят из таблицы, вы можете попробовать что-то вроде этого:

DECLARE @SearchFor TABLE(LookUpNumber INT);
INSERT INTO @SearchFor VALUES(123),(456),(789);

SELECT *
FROM @users
CROSS APPLY(SELECT CONCAT((SELECT CONCAT(',',LookUpNumber) FROM @SearchFor FOR XML PATH('')),','))  A(SearchFor)
WHERE meta.exist('/users/user[@key="location" and contains(sql:column("SearchFor"),concat(",",@value,","))]')=1;

APPLY создаст объединенный список значений на лету и передаст его в XML с помощью sql:column().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...