Найти, если список содержит несколько значений - SQL Server Xquery - PullRequest
0 голосов
/ 14 мая 2018

Я храню данные XML в таблице с именем BikeTable.Данные XML поступают от объекта, который сериализуется с использованием сериализатора .Net.BikeTable будет выглядеть так:

Id - UniqueIdentifier
XmlData - XML

XML, хранящийся в столбце XmlData, выглядит следующим образом:

Запись 1:

<Bike>
    <Material>
        <Cage>EIECH</Cage>
        <Mpn>B258-C436-B001</
    </Material>
    <Roles>
        <string>Race</string>
        <string>Mountain</string>
        <string>City</string>
    </Roles>
</Bike>

Запись2:

<Bike>
    <Material>
        <Cage>ABCDE</Cage>
        <Mpn>B258-C436-B001</Mpn>
    </Material>
    <Roles>
        <string>Race</string>
    </Roles>
</Bike>

Я хочу иметь возможность найти записи в моей таблице, которые будут содержать, например, Race and Mountain.

Пример, если я хочу, чтобы идентификаторы записи, содержащей «Дорога» и «Гора», я нашел только так:

select Id 
from BikeTable
where XmlData.exist('/Bike/Roles/string[contains(., "Road")]') = 1 
   or XmlData.exist('/Bike/Roles/string[contains(., "Mountain")]') = 1

Мне не нравится эта опция, потому чтоэто заставляет меня сгенерировать запрос, если я хочу найти записи, которые соответствуют одной или нескольким ролям. Роли могут содержать неограниченное количество значений, и мне нужно иметь возможность найти записи, которые будут иметь одно или несколько значений. Например: записи, содержащие Race, записи, содержащие Race или Montain, записи, содержащие City, записи, содержащие City и Mountain и т. д.

Можно ли узнать, содержит ли список несколько значений?

1 Ответ

0 голосов
/ 14 мая 2018

Да, вы можете. Это немного догадка, так как вы говорите, что хотите сделать SELECT *; то, что невозможно предоставить какие-либо данные без DDL таблицы. Таким образом, вместо этого я вернул клетку и Mpn мотоцикла:

CREATE TABLE BikeTable (xmlData xml);

--The Close tag for Mpn was missing in your sample data, I assume it wasn't mean to be
INSERT INTO BikeTable
VALUES('<Bike>
    <Material>
        <Cage>EIECH</Cage>
        <Mpn>B258-C436-B001</Mpn>
    </Material>
    <Roles>
        <string>Race</string>
        <string>Mountain</string>
        <string>City</string>
    </Roles>
</Bike>')
GO
WITH Bikes AS (
    SELECT B.Material.value('(Cage/text())[1]','varchar(15)') AS Cage, --Data Type guessed
           B.Material.value('(Mpn/text())[1]','varchar(15)') AS Mpn, --Data Type guessed
           BR.String.value('(./text())[1]','varchar(15)') AS String --Data Type guessed
    FROM BikeTable BT
         CROSS APPLY BT.xmlData.nodes('/Bike/Material') B(Material)
         CROSS APPLY BT.xmlData.nodes('/Bike/Roles/string') BR(String))
SELECT Cage, Mpn
FROM Bikes
GROUP BY Cage, Mpn
HAVING COUNT(String) > 1;

GO

DROP TABLE BikeTable;
...