Как обновить XML в SQL на основе значений в этом XML
Я должен обновить XML таблицы на основе некоторых условий этого 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>
Каждая страна может иметь несколько мест. Я должен сгруппировать на основе Country и Places, затем я должен обновить PlaceValues до нуля для PlaceValue = 0, кроме 0, который непосредственно предшествует PlaceValue > 1. Пример в этом примере, для Country = Brazil и PlaceName = 1, PlaceValue для Месяц1 - Месяц2 будет нулевым, но Месяц3 останется 0, как и предыдущий Месяц4, что больше 0.
3 ответа
В принципе, я вижу 2 способа борьбы с этим. Сначала разделите xml на sql 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>
Второй способ - использовать xquery внутри самого xml.
Ответ на самом деле зависит от того, что вы подразумеваете под "непосредственно предшествующим PlaceValue> 1". Я предположил, что это означает - месяц перед месяцем со значением> 1.
Вам нужно использовать метод.modify() типа данных xml (см. Здесь: https://msdn.microsoft.com/en-us/library/ms187093.aspx) и XQuery, чтобы найти узлы, которые вы должны изменить. Вы можете найти несколько хороших примеров по этой ссылке: http://www.mssqltips.com/sqlservertip/2738/examples-of-using-xquery-to-update-xml-data-in-sql-server/
Если вы хорошо используете 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