我本人对 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')
虽然我想不出一个好方法来计算 distinct 参数。您可能能够充分信任您的搜索条件,从而认为这没有必要。