2012-09-06 59 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

如何從另一組過濾器中指出一組過濾器? –