2009-07-15 72 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') 

雖然從我的頭頂,我想不出一個好的方法就在年底有算不同參數。您可能能夠充分信任您的搜索條件以認爲這是不必要的。