Select XML 列中的数据,某些值除外 T-SQL

Select XML data from column except certain values T-SQL

我有以下 tables

CREATE TABLE #Table1(XMLValue XML);

INSERT INTO #table1
VALUES
       (
       '<Root>
  <row>
    <VendorPlantName>Plant 1</VendorPlantName>
    <TotalAttainableUnits>3693</TotalAttainableUnits>
  </row>
  <row>
    <VendorPlantName>Plant 2</VendorPlantName>
    <TotalAttainableUnits>69477</TotalAttainableUnits>
  </row>
  <row>
    <VendorPlantName>Plant 3</VendorPlantName>
    <TotalAttainableUnits>573</TotalAttainableUnits>
  </row>
  </Root>'
       );

CREATE TABLE #Table2
(NodeName  NVARCHAR(255)
,NodeValue NVARCHAR(255)
);

INSERT INTO #table2
VALUES
       (
       'VendorPlantName','Plant 2'
       ),
       (
       'VendorPlantName','Plant 1'
       );

有了这 2 tables,是否有可能在合理的范围内产生以下输出。

<Root>
  <row>
    <VendorPlantName>Plant 3</VendorPlantName>
    <TotalAttainableUnits>573</TotalAttainableUnits>
  </row>
<Root>

更多细节。完全动态的XML。节点名和值也将是未知的。是否有可能(使用 SQL serve 2008 R2)仅 select xml 文档中未出现在第二个 table.[=15 中的节点和值=]

用例只有 return 个以前从未见过的节点名称和值。作为带有一些连接的动态 sql 查询,这会容易得多,但我不能那样做。任何帮助表示赞赏。即使答案是另辟蹊径。

我不知道 “XML 将是完全动态的” 的真正含义。看起来,总会有 <Root> 和很多 <row> 元素。所以动态部分是每个 <row> 中的未知字段列表。正确吗?

你可以试试这个:

DECLARE @tbl1 TABLE(XMLValue XML);

INSERT INTO @tbl1
VALUES
       (
       '<Root>
  <row>
    <VendorPlantName>Plant 1</VendorPlantName>
    <TotalAttainableUnits>3693</TotalAttainableUnits>
  </row>
  <row>
    <VendorPlantName>Plant 2</VendorPlantName>
    <TotalAttainableUnits>69477</TotalAttainableUnits>
  </row>
  <row>
    <VendorPlantName>Plant 3</VendorPlantName>
    <TotalAttainableUnits>573</TotalAttainableUnits>
  </row>
  </Root>'
       );

DECLARE @tbl2 TABLE(NodeName  NVARCHAR(255)
                   ,NodeValue NVARCHAR(255)
                    );

INSERT INTO @tbl2
VALUES
       (
       'VendorPlantName','Plant 2'
       ),
       (
       'VendorPlantName','Plant 1'
       );

--cte创建排除列表

WITH ExcludeFields(ExclFld) AS
(
    SELECT NodeName AS [@nn]
          ,NodeValue AS [@nv] 
    FROM @tbl2 t2
    FOR XML PATH('exclFld'),TYPE
)
SELECT Combined.query('
                      <Root> 
                      { 
                          for $rw in /row
                          return 
                          <row>
                          {
                            for $fld in $rw/*
                            return
                            if(/exclFld[@nn=local-name($fld)]/@nv=$fld/text()) then
                            <x/>
                            else
                            $fld
                          }
                          </row>
                      }
                      </Root>
                      ')
               .query('/Root/row[empty(x)]')

FROM ExcludeFields ef
CROSS JOIN @tbl1 t1
CROSS APPLY(SELECT ef.ExclFld AS [*]
                  ,t1.XMLValue.query('/Root/row')
            FOR XML PATH(''),TYPE) A(Combined);

简而言之:

我们创建了一个包含您的行和排除字段列表的中间 XML:

<exclFld nn="VendorPlantName" nv="Plant 2" />
<exclFld nn="VendorPlantName" nv="Plant 1" />
<row>
  <VendorPlantName>Plant 1</VendorPlantName>
  <TotalAttainableUnits>3693</TotalAttainableUnits>
</row>
<row>
  <VendorPlantName>Plant 2</VendorPlantName>
  <TotalAttainableUnits>69477</TotalAttainableUnits>
</row>
<row>
  <VendorPlantName>Plant 3</VendorPlantName>
  <TotalAttainableUnits>573</TotalAttainableUnits>
</row>

不,我们可以使用 XQuery-FLWOR 方法 运行 遍历每一行,然后遍历每个字段,并且 return a <x/> 如果节点名称和节点-值存在于排除字段列表中。

有了这个 XML 我们可以 运行 另一个 XQuery 只获取没有 <x>.

的行

另一种方法

...您可以将其切碎并使用 标准 SQL 进行艰苦的工作:

WITH TheRows AS
(          
    SELECT ROW_NUMBER() OVER(ORDER BY A.rw) AS RowNumber
          ,rw.query('.') TheRow
    FROM @tbl1 t1
    CROSS APPLY t1.XMLValue.nodes('/Root/row') A(rw)
)
,EAV AS
(
    SELECT r.RowNumber
          ,fld.value('local-name(.)','nvarchar(1000)') AS FieldName
          ,fld.value('text()[1]','nvarchar(1000)') AS FieldValue 
    FROM TheRows r
    CROSS APPLY r.TheRow.nodes('row/*') Each(fld)
)
,SkipRows AS
(
    SELECT EAV.RowNumber
    FROM EAV
    WHERE EXISTS(SELECT 1 FROM @tbl2 t2 WHERE t2.NodeName=EAV.FieldName AND t2.NodeValue=EAV.FieldValue)
    GROUP BY EAV.RowNumber
)
SELECT *
FROM EAV
WHERE EAV.RowNumber NOT IN (SELECT sr.RowNumber FROM SkipRows sr);

最后的结果可以很容易地 return 编辑为 XML - 如果需要的话。