Я ненавижу циклы в SQL-сервере ... Иногда мы не можем избежать этого, но в большинстве случаев есть другие подходы, и в большинстве случаев эти подходы на основе множеств лучше:
Вы, кажется, ненужно объявить пространства имен, чтобы я их отпустил ...
Я немного уменьшил это, так что это может не полностью соответствовать вашим потребностям.Дайте мне знать, если чего-то не хватает:
DECLARE @ConfigMaster TABLE (
[ConfigCode] [nvarchar](15) NOT NULL,
[ConfigMaster] [xml] NOT NULL
)
INSERT @configMaster (ConfigCode, [ConfigMaster])
values('TestPart01', '<ConfigMaster xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Components>
<Component Name="FRSTK">
<Attributes>
<Attribute Name="O-FLGOPT" Value="N" OptionListId="YES_NO" PrintCode="3" DataEntryOrder="22" />
<Attribute Name="O-GRDLGT" Value="0" OptionListId="" PrintCode="" DataEntryOrder="0" />
<Attribute Name="O-LEADLG" Value="72" OptionListId="" PrintCode="D" DataEntryOrder="4" />
<Attribute Name="O-LEADTP" Value="R" OptionListId="1F3" PrintCode="D" DataEntryOrder="3" />
<Attribute Name="O-LOCOPT" Value="N" OptionListId="YES_NO" PrintCode="3" DataEntryOrder="24" />
<Attribute Name="O-CODE" Value="N18A13" OptionListId="1F1" PrintCode="D" DataEntryOrder="1" />
<Attribute Name="O-CONOPT" Value="N" OptionListId="YES_NO" PrintCode="3" DataEntryOrder="25" />
<Attribute Name="O-FITOPT" Value="Y" OptionListId="YES_NO" PrintCode="3" DataEntryOrder="23" />
<Attribute Name="O-FITTIN" Value="BG" OptionListId="1F5" PrintCode="D" DataEntryOrder="32" />
<Attribute Name="O-FLANGE" Value="" OptionListId="1F2" PrintCode="" DataEntryOrder="0" />
</Attributes>
</Component>
</Components>
</ConfigMaster>')
select * from @ConfigMaster; --before
- безобразная грубая сила, но easy-cheesy-one-line ...
UPDATE @ConfigMaster SET ConfigMaster=
REPLACE(REPLACE(REPLACE(CAST(ConfigMaster AS NVARCHAR(MAX)),' PrintCode="D"',' PrintCode="E"'),' PrintCode="3"',' PrintCode="I"'),' PrintCode=""',' PrintCode="I"');
--XQuery, если ограничения приемлемы для вас (при условии, что их может быть больше, чем один <Component>
):
UPDATE @ConfigMaster SET ConfigMaster=
ConfigMaster.query
(N'
<ConfigMaster>
<Components>
{
for $comp in //ConfigMaster/Components/Component
return
<Component>{$comp/@Name}
<Attributes>
{
for $node in $comp/Attributes/Attribute
return
<Attribute>
{
for $attr in $node/@*
return
if(local-name($attr)!="PrintCode") then
$attr
else
attribute PrintCode {if($attr="D") then "E" else "I"}
}
</Attribute>
}
</Attributes>
</Component>
}
</Components>
</ConfigMaster>
');
- и, наконец, декомпозиция / перекомпоновка (при условии, что может быть несколько компонентов)
WITH comp AS
(
SELECT comp.value(N'@Name',N'nvarchar(max)') AS ComponentName
,comp.query(N'*') AS Children
FROM @ConfigMaster
CROSS APPLY ConfigMaster.nodes(N'/ConfigMaster/Components/Component') A(comp)
)
SELECT ComponentName AS [ComponentName/@Name]
,(
SELECT attr.value(N'@Name',N'nvarchar(max)') AS [@Name]
,attr.value(N'@Value',N'nvarchar(max)') AS [@Value]
,attr.value(N'@OptionListId',N'nvarchar(max)') AS [@OptionListId]
,CASE attr.value(N'@PrintCode',N'nvarchar(max)') WHEN 'D' THEN 'E' ELSE 'I' END AS [@PrintCode]
,attr.value(N'@DataEntryOrder',N'nvarchar(max)') AS [@DataEntryOrde]
FROM Children.nodes(N'Attributes/Attribute') A(attr)
FOR XML PATH('Attribute'),ROOT('Attributes'),TYPE
)
FROM comp
FOR XML PATH('Components'),ROOT('ConfigMaster')