我不确定如何正确地说出来,但我对Sql Server中的XML非常(非常)新。
我在表中定义了一个XML列,如果Xml列中的数据与预定义列表中的元素匹配,我想检索记录的id。
数据看起来有点像这样:
<Parameters>
<Parameter>
<Name>Param1</Name>
<Value>Value1</Value>
</Parameter>
<Parameter>
<Name>Param2</Name>
<Value>Value2</Value>
</Parameter>
</Parameter>
我想要检查的是,类似的参数和值列表是否与Xml列的列表相匹配。我可以看到你无法在Sql Server中进行Xml比较。
我可以为一个参数做到这一点:
select * from table where
parameters.value('(/Parameters/Parameter/Name)[1]', 'varchar(50)') = 'Param1'
and
parameters.value('(/Parameters/Parameter/Value)[1]', 'varchar(50)') = 'Value1'
但是我想要一些可以处理任何数量参数的东西。
答案 0 :(得分:1)
您可以使用.nodes()运算符将XML投影到列中,然后比较投影列。这通常使用CROSS APPLY来完成,就像这样(从内存中输入):
SELECT x.value('(Name)[1]', 'varchar(50)') as Name
, x.value('(Value)[1]', 'varchar(50)') as Value
from Table
CROSS APPLY parameters.nodes('/Parameters/Parameter') AS t(x);
您可以在CTE中使用此SELECT:
WITH shredded_xml AS (
SELECT Table.ID
, x.value('(Name)[1]', 'varchar(50)') as Name
, x.value('(Value)[1]', 'varchar(50)') as Value
from Table
CROSS APPLY parameters.nodes('/Parameters/Parameter') AS t(x))
SELECT *
FROM shredded_xml
WHERE Name = 'Param1'
AND Value = 'Value1';
答案 1 :(得分:1)
我自己对SQL XML相当新,所以可能有一种比这更好的方法,但看起来很优雅:
-- Set up some sample data
CREATE TABLE Data (
Id int
, Attributes xml
)
-- Number 1 is red and small
INSERT Data
VALUES ( 1, '
<Parameters>
<Parameter>
<Name>Color</Name>
<Value>Red</Value>
</Parameter>
<Parameter>
<Name>Size</Name>
<Value>Small</Value>
</Parameter>
</Parameters>' )
-- Number 2 is blue and large
INSERT Data
VALUES ( 2, '
<Parameters>
<Parameter>
<Name>Color</Name>
<Value>Blue</Value>
</Parameter>
<Parameter>
<Name>Size</Name>
<Value>Large</Value>
</Parameter>
</Parameters>' )
-- Number 3 is Large
INSERT Data
VALUES ( 3, '
<Parameters>
<Parameter>
<Name>Size</Name>
<Value>Large</Value>
</Parameter>
</Parameters>' )
-- Search for large ones
DECLARE @searchCriteriaXml xml
SET @searchCriteriaXml = '<Parameters>
<Parameter>
<Name>Size</Name>
<Value>Large</Value>
</Parameter>
</Parameters>'
/*
-- Or for large blue ones:
SET @searchCriteriaXml = '<Parameters>
<Parameter>
<Name>Size</Name>
<Value>Large</Value>
</Parameter>
<Parameter>
<Name>Color</Name>
<Value>Blue</Value>
</Parameter>
</Parameters>'
*/
-- *************************************
-- Here begins the search process
-- Shred the search criteria into a rowset
DECLARE @searchCriteria TABLE (
Name nvarchar(100)
, Value nvarchar(100)
)
INSERT INTO
@searchCriteria
SELECT DISTINCT
P.value('Name[1]', 'nvarchar(100)')
, P.value('Value[1]', 'nvarchar(100)')
FROM
@searchCriteriaXml.nodes('/Parameters/Parameter') SC(P)
-- Debug:
-- SELECT * FROM @searchCriteria
-- To find matching items, we want to shred each
-- item's xml, INNER JOIN against the search criteria,
-- and return those Ids that matched exactly as many rows
-- as there are in the criteria
SELECT
Id
FROM
(
SELECT
Data.Id
, P.value('Name[1]', 'nvarchar(100)') ParameterName
, P.value('Value[1]', 'nvarchar(100)') ParameterValue
FROM
Data
CROSS APPLY Attributes.nodes('/Parameters/Parameter') D(P)
) D -- the shredded data
INNER JOIN @searchCriteria SC
ON D.ParameterName = SC.Name
AND D.ParameterValue = SC.Value
GROUP BY Id
HAVING COUNT(*) = (SELECT COUNT(*) FROM @searchCriteria)
DROP TABLE Data
事实上,我想,考虑到这一点,没有特别的理由明确将搜索条件提取到该表变量中 - 我们也只是在连接操作本身中将其粉碎:
SELECT
Id
FROM
(
SELECT
Data.Id
, P.value('Name[1]', 'nvarchar(100)') ParameterName
, P.value('Value[1]', 'nvarchar(100)') ParameterValue
FROM
Data
CROSS APPLY Attributes.nodes('/Parameters/Parameter') D(P)
) D -- the shredded data
INNER JOIN
(
SELECT DISTINCT
P.value('Name[1]', 'nvarchar(100)') Name
, P.value('Value[1]', 'nvarchar(100)') Value
FROM
@searchCriteriaXml.nodes('/Parameters/Parameter') SC(P)
) SC -- the shredded search criteria
ON D.ParameterName = SC.Name
AND D.ParameterValue = SC.Value
GROUP BY Id
HAVING COUNT(*) = @searchCriteriaXml.value('count(/Parameters/Parameter)', 'int')
尽管我不知道如何在最后计算不同的参数的好方法。您可以充分信任您的搜索条件,认为这是不必要的。