2009-07-15 48 views
0

我不知道如何正确地输入这个信息,但我对Sql Server中的XML非常(非常)新。迭代Xml Column元素和对Xml的comapre变量

我在表中定义了一个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

所有参数名称和值是否真的保存在* single * Parameter元素中?这会让事情变得有趣 – AakashM 2009-07-15 16:33:03

+0

对不起,你是对的,我的错误,编辑。 – MrEdmundo 2009-07-15 16:34:18

+0

谢谢。现在你能说出传入'必须匹配所有这些'数据的格式吗?它是否采用类似的XML格式 - 或逗号分隔的字符串 - 或表格? – AakashM 2009-07-15 16:37:16

回答

1

您可以使用.nodes()运算符将您的XML投影到列中,然后比较投影列。这通常是交叉进行适用,像这样(打字从内存中):

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

我自己是相当新的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 

其实我想,思考它,有没有什么特别的理由,明确拉搜索标准成表VA可变结构 - 我们只是以及只撕碎它在连接操作本身:

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') 

虽然从我的头顶,我想不出一个好的方法就在年底有算不同参数。您可能能够充分信任您的搜索条件以认为这是不必要的。