如何根据 XML 中的值更新 SQL 中的 XML
How to Update XML in SQL based on values in that XML
我必须根据 XML 的某些条件更新 table 的 XML。示例 XML:
<CountryValues>
<CountryRow>
<CountryName>Brazil</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>1</Month>
<PlaceValue>0</PlaceValue>
</CountryRow>
<CountryRow>
<CountryName>Brazil</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>2</Month>
<PlaceValue>0</PlaceValue>
</CountryRow>
<CountryRow>
<CountryName>Brazil</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>3</Month>
<PlaceValue>0</PlaceValue>
</CountryRow>
<CountryRow>
<CountryName>Brazil</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>4</Month>
<PlaceValue>10</PlaceValue>
</CountryRow>
<CountryRow>
<CountryName>Australia</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>1</Month>
<PlaceValue>0</PlaceValue>
</CountryRow>
<CountryRow>
<CountryName>Australia</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>1</Month>
<PlaceValue>0</PlaceValue>
</CountryRow>
<CountryRow>
<CountryName>Australia</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>1</Month>
<PlaceValue>4</PlaceValue>
</CountryRow>
</CountryValues>
每个国家可以有多个地点。我必须根据国家和地点进行分组,然后我必须将 PlaceValues 更新为 null,因为 PlaceValue = 0 除了紧接在 PlaceValue > 1 之前的 0。在此示例中,对于 Country = Brazil 和 PlaceName = 1,PlaceValue 为Month1 到 Month2 将为 Null,但 Month3 将保持 0,因为它前面的 Month4 大于 0。
如果您使用 C# 没问题,您应该看看 XDocument。
示例:
XDocument document = XDocument.Parse("<CountryValues><CountryRow><CountryName>Brazil</CountryName><PlaceName>Place 1</PlaceName><Month>1</Month><PlaceValue>0</PlaceValue> </CountryRow><CountryRow><CountryName>Brazil</CountryName><PlaceName>Place 1</PlaceName><Month>2</Month><PlaceValue>0</PlaceValue> </CountryRow><CountryRow><CountryName>Brazil</CountryName><PlaceName>Place 1</PlaceName><Month>3</Month><PlaceValue>0</PlaceValue> </CountryRow><CountryRow><CountryName>Brazil</CountryName><PlaceName>Place 1</PlaceName><Month>4</Month><PlaceValue>10</PlaceValue> </CountryRow><CountryRow><CountryName>Australia</CountryName><PlaceName>Place 1</PlaceName><Month>1</Month><PlaceValue>0</PlaceValue> </CountryRow><CountryRow><CountryName>Australia</CountryName><PlaceName>Place 1</PlaceName><Month>1</Month><PlaceValue>0</PlaceValue> </CountryRow><CountryRow><CountryName>Australia</CountryName><PlaceName>Place 1</PlaceName><Month>1</Month><PlaceValue>4</PlaceValue> </CountryRow></CountryValues>");
var countries = document.Root.Elements("CountryRow");
foreach (var country in countries)
{
//Do your work here
//You can access sub element like so :
Console.WriteLine (country.Element("CountryName").Value);
}
输出:
Brazil
Brazil
Brazil
Brazil
Australia
Australia
Australia
您需要使用 xml 数据类型的 .modify() 方法(参见此处:https://msdn.microsoft.com/en-us/library/ms187093.aspx)和 XQuery 来查找您应该更改的节点。
您可以在 link 中找到一些不错的示例:http://www.mssqltips.com/sqlservertip/2738/examples-of-using-xquery-to-update-xml-data-in-sql-server/
基本上,我看到了两种处理方法。首先 - 将 xml 拆分为 sql table/derived table,完成您的工作,然后再次组合成 xml。
declare @data xml =
'<CountryValues>
<CountryRow>
<CountryName>Brazil</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>1</Month>
<PlaceValue>0</PlaceValue>
</CountryRow>
<CountryRow>
<CountryName>Brazil</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>2</Month>
<PlaceValue>0</PlaceValue>
</CountryRow>
<CountryRow>
<CountryName>Brazil</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>3</Month>
<PlaceValue>0</PlaceValue>
</CountryRow>
<CountryRow>
<CountryName>Brazil</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>4</Month>
<PlaceValue>10</PlaceValue>
</CountryRow>
</CountryValues>'
;with cte as (
select
t.c.value('CountryName[1]', 'nvarchar(max)') as CountryName,
t.c.value('PlaceName[1]', 'nvarchar(max)') as PlaceName,
t.c.value('Month[1]', 'int') as [Month],
t.c.value('PlaceValue[1]', 'int') as PlaceValue
from @data.nodes('CountryValues/CountryRow') as t(c)
)
select
c1.CountryName,
c1.PlaceName,
c1.[Month],
case
when c1.PlaceValue = 0 and isnull(c2.PlaceValue, 0) <= 1 then null
else c1.PlaceValue
end as PlaceValue
from cte as c1
left outer join cte as c2 on c2.CountryName = c1.CountryName and c2.PlaceName = c1.PlaceName and c2.[Month] = c1.[Month] + 1
for xml path('CountryRow'), root('CountryValues')
----------------------------------
<CountryValues>
<CountryRow>
<CountryName>Brazil</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>1</Month>
</CountryRow>
<CountryRow>
<CountryName>Brazil</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>2</Month>
</CountryRow>
<CountryRow>
<CountryName>Brazil</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>3</Month>
<PlaceValue>0</PlaceValue>
</CountryRow>
<CountryRow>
<CountryName>Brazil</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>4</Month>
<PlaceValue>10</PlaceValue>
</CountryRow>
</CountryValues>
第二种方法是在 xml 本身内部使用 xquery。
答案实际上取决于"immediately preceding PlaceValue > 1"是什么意思。我在这里假设这意味着 - 值 > 1 的月份之前的月份。
我必须根据 XML 的某些条件更新 table 的 XML。示例 XML:
<CountryValues>
<CountryRow>
<CountryName>Brazil</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>1</Month>
<PlaceValue>0</PlaceValue>
</CountryRow>
<CountryRow>
<CountryName>Brazil</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>2</Month>
<PlaceValue>0</PlaceValue>
</CountryRow>
<CountryRow>
<CountryName>Brazil</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>3</Month>
<PlaceValue>0</PlaceValue>
</CountryRow>
<CountryRow>
<CountryName>Brazil</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>4</Month>
<PlaceValue>10</PlaceValue>
</CountryRow>
<CountryRow>
<CountryName>Australia</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>1</Month>
<PlaceValue>0</PlaceValue>
</CountryRow>
<CountryRow>
<CountryName>Australia</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>1</Month>
<PlaceValue>0</PlaceValue>
</CountryRow>
<CountryRow>
<CountryName>Australia</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>1</Month>
<PlaceValue>4</PlaceValue>
</CountryRow>
</CountryValues>
每个国家可以有多个地点。我必须根据国家和地点进行分组,然后我必须将 PlaceValues 更新为 null,因为 PlaceValue = 0 除了紧接在 PlaceValue > 1 之前的 0。在此示例中,对于 Country = Brazil 和 PlaceName = 1,PlaceValue 为Month1 到 Month2 将为 Null,但 Month3 将保持 0,因为它前面的 Month4 大于 0。
如果您使用 C# 没问题,您应该看看 XDocument。
示例:
XDocument document = XDocument.Parse("<CountryValues><CountryRow><CountryName>Brazil</CountryName><PlaceName>Place 1</PlaceName><Month>1</Month><PlaceValue>0</PlaceValue> </CountryRow><CountryRow><CountryName>Brazil</CountryName><PlaceName>Place 1</PlaceName><Month>2</Month><PlaceValue>0</PlaceValue> </CountryRow><CountryRow><CountryName>Brazil</CountryName><PlaceName>Place 1</PlaceName><Month>3</Month><PlaceValue>0</PlaceValue> </CountryRow><CountryRow><CountryName>Brazil</CountryName><PlaceName>Place 1</PlaceName><Month>4</Month><PlaceValue>10</PlaceValue> </CountryRow><CountryRow><CountryName>Australia</CountryName><PlaceName>Place 1</PlaceName><Month>1</Month><PlaceValue>0</PlaceValue> </CountryRow><CountryRow><CountryName>Australia</CountryName><PlaceName>Place 1</PlaceName><Month>1</Month><PlaceValue>0</PlaceValue> </CountryRow><CountryRow><CountryName>Australia</CountryName><PlaceName>Place 1</PlaceName><Month>1</Month><PlaceValue>4</PlaceValue> </CountryRow></CountryValues>");
var countries = document.Root.Elements("CountryRow");
foreach (var country in countries)
{
//Do your work here
//You can access sub element like so :
Console.WriteLine (country.Element("CountryName").Value);
}
输出:
Brazil
Brazil
Brazil
Brazil
Australia
Australia
Australia
您需要使用 xml 数据类型的 .modify() 方法(参见此处:https://msdn.microsoft.com/en-us/library/ms187093.aspx)和 XQuery 来查找您应该更改的节点。 您可以在 link 中找到一些不错的示例:http://www.mssqltips.com/sqlservertip/2738/examples-of-using-xquery-to-update-xml-data-in-sql-server/
基本上,我看到了两种处理方法。首先 - 将 xml 拆分为 sql table/derived table,完成您的工作,然后再次组合成 xml。
declare @data xml =
'<CountryValues>
<CountryRow>
<CountryName>Brazil</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>1</Month>
<PlaceValue>0</PlaceValue>
</CountryRow>
<CountryRow>
<CountryName>Brazil</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>2</Month>
<PlaceValue>0</PlaceValue>
</CountryRow>
<CountryRow>
<CountryName>Brazil</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>3</Month>
<PlaceValue>0</PlaceValue>
</CountryRow>
<CountryRow>
<CountryName>Brazil</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>4</Month>
<PlaceValue>10</PlaceValue>
</CountryRow>
</CountryValues>'
;with cte as (
select
t.c.value('CountryName[1]', 'nvarchar(max)') as CountryName,
t.c.value('PlaceName[1]', 'nvarchar(max)') as PlaceName,
t.c.value('Month[1]', 'int') as [Month],
t.c.value('PlaceValue[1]', 'int') as PlaceValue
from @data.nodes('CountryValues/CountryRow') as t(c)
)
select
c1.CountryName,
c1.PlaceName,
c1.[Month],
case
when c1.PlaceValue = 0 and isnull(c2.PlaceValue, 0) <= 1 then null
else c1.PlaceValue
end as PlaceValue
from cte as c1
left outer join cte as c2 on c2.CountryName = c1.CountryName and c2.PlaceName = c1.PlaceName and c2.[Month] = c1.[Month] + 1
for xml path('CountryRow'), root('CountryValues')
----------------------------------
<CountryValues>
<CountryRow>
<CountryName>Brazil</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>1</Month>
</CountryRow>
<CountryRow>
<CountryName>Brazil</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>2</Month>
</CountryRow>
<CountryRow>
<CountryName>Brazil</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>3</Month>
<PlaceValue>0</PlaceValue>
</CountryRow>
<CountryRow>
<CountryName>Brazil</CountryName>
<PlaceName>Place 1</PlaceName>
<Month>4</Month>
<PlaceValue>10</PlaceValue>
</CountryRow>
</CountryValues>
第二种方法是在 xml 本身内部使用 xquery。
答案实际上取决于"immediately preceding PlaceValue > 1"是什么意思。我在这里假设这意味着 - 值 > 1 的月份之前的月份。