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 - 如果需要的话。
我有以下 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 - 如果需要的话。