2012-09-06 20 views
1

我想通过将它连接到一个条件表来找到一种方法来对XML字符串进行接受/拒绝。我现在有一个“过滤器”正在工作,但是要编写它以便可以过滤2个或更多。t-sql:在多个条件下动态过滤XML?

下面是与两者中的一个匹配的代码。如果两者匹配,则会过滤字符串。 我想要做的就是它,所以它必须同时匹配,同时还留下了选择单条件

CREATE TABLE #filter (exclusion_type CHAR(1), excluded_value varchar(10)) 
INSERT INTO #filter VALUES ('B','boy') 
INSERT INTO #filter VALUES ('C','cat') 

DECLARE @data XML 
SELECT @data = '<A><B>boy</B><C>cat</C></A>' 
SELECT * FROM (SELECT CONVERT(VARCHAR(128),node.query('fn:local-name(.)')) AS NodeName, CONVERT(VARCHAR(MAX),node.query('./text()')) AS NodeValue 
FROM @data.nodes(N'//*') T(node))xml_shred 

IF NOT EXISTS 
(SELECT * FROM (SELECT CONVERT(VARCHAR(128),node.query('fn:local-name(.)')) AS NodeName, CONVERT(VARCHAR(MAX),node.query('./text()')) AS NodeValue 
FROM @data.nodes(N'//*') T(node)) xml_shred 
INNER JOIN #filter 
ON (nodename = exclusion_type AND nodevalue LIKE excluded_value) 
) 
select 'record would be inserted ' 
ELSE select 'record was filtered' 

这里是我现在怎么把它过滤两种。丑陋,不可扩展。

IF NOT EXISTS 
(SELECT * FROM (SELECT CONVERT(VARCHAR(128),node.query('fn:local-name(.)')) AS NodeName, CONVERT(VARCHAR(MAX),node.query('./text()')) AS NodeValue 
FROM @data.nodes(N'//*') T(node)) xml_shred 
INNER JOIN #filter 
ON (nodename = exclusion_type AND nodevalue LIKE excluded_value) 
) 
--combination filters don't easily work within that xml_shred 
and not(
     @data.value('(/A/B)[1]', 'varchar(128)') = 'boy' 
     AND 
     @data.value('(/A/C)[1]', 'varchar(128)')='cat' 
     ) 

select 'record would be inserted ' 
ELSE select 'record was filtered' 

我唯一的其他想法:

  • 某种GUID的,将在#filter表链接记录在一起,然后内部联接上的#filtertable一个GROUP BY,由GUID和分组使用SUM来匹配记录的数量。
  • 使用分号分割#filter行,然后使用CTE或某物来伪造层次结构并从那里开始工作。

通过的Mikael的建议

CREATE TABLE #filter 
    (
     exclusion_set SMALLINT, 
     exclusion_type CHAR(1) , 
     excluded_value VARCHAR(10) 
    ) 
INSERT INTO #filter 
VALUES (1, 'B', 'boy') 
INSERT INTO #filter 
VALUES (1, 'C', 'cat') 
INSERT INTO #filter 
VALUES (2, 'D', 'dog') 

DECLARE @data XML 
SELECT @data = '<A><B>boy</B><C>cat</C></A>' 
IF NOT EXISTS(
SELECT * FROM 
(
select COUNT(*) AS match_count, exclusion_set 
       from #filter as F 
       where exists (
          select * 
          from (
           select X.N.value('local-name(.)', 'varchar(128)') as  NodeName, 
             X.N.value('./text()[1]', 'varchar(max)') as  NodeValue 
           from @data.nodes('//*') as X(N) 
           ) T 
          where T.NodeName = F.exclusion_type and 
           T.NodeValue like F.excluded_value 
          ) 
GROUP BY exclusion_set 
) matches_per_set 
INNER JOIN 
(SELECT COUNT(*) AS total_count, exclusion_set FROM #filter GROUP BY exclusion_set)  grouped_set 
ON match_count = total_count 
AND grouped_set.exclusion_set = matches_per_set.exclusion_set 
) 

回答

0

做,因为如果我不标记的东西作为回答,我包括从上面我的我显然得到丁当作响代码更改。非常感谢Mikael Eriksson的帮助。他的XML碎片比我的要快,并且通过添加“exclusion_set”字段(char(2)使其明显不是一个IDENTITY或主键),我可以执行多项检查。如果一个集合中的所有条件匹配,那么该记录被过滤。


CREATE TABLE #filter 
    (
     exclusion_set CHAR(2), 
     exclusion_type CHAR(1) , 
     excluded_value VARCHAR(10) 
    ) 
INSERT INTO #filter 
VALUES ('aa', 'B', 'boy') 
INSERT INTO #filter 
VALUES ('aa', 'C', 'cat') 
INSERT INTO #filter 
VALUES ('ab', 'D', 'dog') 

DECLARE @data XML 
SELECT @data = '<A><B>boy</B><C>cat</C></A>' 
IF NOT EXISTS(
SELECT * FROM 
(
select COUNT(*) AS match_count, exclusion_set 
       from #filter as F 
       where exists (
          select * 
          from (
           select X.N.value('local-name(.)', 'varchar(128)') as  NodeName, 
             X.N.value('./text()[1]', 'varchar(max)') as  NodeValue 
           from @data.nodes('//*') as X(N) 
           ) T 
          where T.NodeName = F.exclusion_type and 
           T.NodeValue like F.excluded_value 
          ) 
GROUP BY exclusion_set 
) matches_per_set 
INNER JOIN 
(SELECT COUNT(*) AS total_count, exclusion_set FROM #filter GROUP BY exclusion_set)  grouped_set 
ON match_count = total_count 
AND grouped_set.exclusion_set = matches_per_set.exclusion_set 


) 
select 'record would be inserted ' 
else 
    select 'record was filtered' 
3
if not exists (
       select * 
       from #filter as F 
       where exists (
          select * 
          from (
           select X.N.value('local-name(.)', 'varchar(128)') as NodeName, 
             X.N.value('./text()[1]', 'varchar(max)') as NodeValue 
           from @data.nodes('//*') as X(N) 
           ) T 
          where T.NodeName = F.exclusion_type and 
           T.NodeValue like F.excluded_value 
          ) 
       having count(*) = (select count(*) from #filter) 
      ) 
    select 'record would be inserted ' 
else 
    select 'record was filtered' 
+0

权,但是,只有当有永远只能匹配的记录工作。第二个我添加了一组不同的条件(通过向#filter添加行),它失败了。但是,这段代码与我的GUID想法相吻合...... – mbourgon

+0

我在做的node.query与你正在做的X.N.value之间的性能有很大的区别吗?我不知道XML查询足够了解。猜猜我可以对付我的A/B。 – mbourgon

+0

如何从另一组过滤器中指出一组过滤器? –