değiştirmek T-SQL XML nasıl kullanılır / aramak için ( '... değerini değiştirin)' boş özelliklerini değiştirmek

oy
0

Bu iki bölümlü bir sorundur. Parçalar için bileşen ve nitelik verilerini ihtiva eden bir XML sütun içeren bir tablo. Özelliklerinden biri bütün bileşenlerine karşılık güncellenmesi gerekiyor ve tüm kayıtlarda bağlıyor. Aşağıda Technet eşyadan tekniği kullanılarak kısmi bir çözüm Bulunan: https://social.technet.microsoft.com/wiki/contents/articles/28601.t-sql-tips-search-and-replace-string-from-multiple -nodes-içinde-a-xml-document.aspx yetersiz kalıyor:

  1. PrintCode boş bir dize olduğu durumlarda (PrintCode = ) I yaklaşımı değeriyle bunu değiştirmek yerine özgün boş bir dize bırakarak başarısız. $ Arg2 sıfır uzunlukta dize olduğunda işlev daima DOĞRU verir () içeriyor olmasıdır.
  2. İKEN döngü biri Yeni değerine yalnızca bir eski değerini yeniden eşleştirmek için çalışır YOKTUR. Bir geçişte haritalama masa ve güncellenmiş tüm özelliklerini kullanabilecekleri için umuyordum. Birkaç diğer yaklaşımlar denedim ama tek geçişli bir çözüm gelmedik.

Bu verilerin basitleştirilmiş bir şeklidir. Gerçekte yeniden yaptırılması gerek daha birçok kayıt bulunmaktadır.

Mümkünse yerine bir açıklamada güncellemeleri tüm gerçekleştireceklerini tekrar sıfır uzunluklu dize hariç tüm değerleri yeniden eşleme için çalışan kaba kuvvet sürümüne sahip ama yok.

Örnek kod:

    DECLARE @Map TABLE ([Old] VARCHAR(1) NOT NULL, [New] VARCHAR(1) NOT NULL)
insert @Map ([Old], [New])
Values   ('D', 'E'),('3', 'I'),('', 'I');

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

WHILE EXISTS
(
SELECT  *
        FROM    @ConfigMaster
        WHERE   ConfigMaster.exist('//Component/Attributes/Attribute[ contains(@PrintCode, D)]') = 1
)
BEGIN
         UPDATE [m]
         SET ConfigMaster.modify('replace value of 
                                    (//Component/Attributes/Attribute[ contains(@PrintCode , D)]/@PrintCode)[1] 
                                  with sql:column(New) ')
         FROM
         (
              SELECT  ConfigMaster,
                        t.u.value('./@PrintCode[1]','varchar(1)') AS OrigValue
              FROM    @ConfigMaster as [p]
              CROSS APPLY p.ConfigMaster.nodes('/ConfigMaster/Components/Component/Attributes/Attribute[ contains(@PrintCode , D)]') as t(u)
         ) as [m]
         Inner join @Map as s on s.Old = m.OrigValue

END
select * from @ConfigMaster --after pass 1: D updated to E
WHILE EXISTS
(
SELECT  *
        FROM    @ConfigMaster
        WHERE   ConfigMaster.exist('//Component/Attributes/Attribute[ contains(@PrintCode, 3)]') = 1
)
BEGIN
         UPDATE [m]
         SET ConfigMaster.modify('replace value of (//Component/Attributes/Attribute[ contains(@PrintCode , 3)]/@PrintCode)[1] with sql:column(New) ')
         FROM
         (
              SELECT  ConfigMaster,
                        t.u.value('./@PrintCode[1]','varchar(1)') AS OrigValue
              FROM    @ConfigMaster as [p]
              CROSS APPLY p.ConfigMaster.nodes('/ConfigMaster/Components/Component/Attributes/Attribute[ contains(@PrintCode , 3)]') as t(u)
         ) as [m]
         Inner join @Map as s on s.Old = m.OrigValue

END
select * from @ConfigMaster --after pass 2: 3 updated to I
WHILE EXISTS
(
SELECT  *
        FROM    @ConfigMaster
        WHERE   ConfigMaster.exist('//Component/Attributes/Attribute[contains(@PrintCode , )]') = 1 --the empty string  has special meaning to the contains() function
)
BEGIN
         UPDATE [m]
         SET ConfigMaster.modify('replace value of (//Component/Attributes/Attribute[ contains(@PrintCode , )]/@PrintCode)[1] with sql:column(New) ')
         FROM
         (
              SELECT  ConfigMaster,
                        t.u.value('./@PrintCode[1]','varchar(1)') AS OrigValue
              FROM    @ConfigMaster as [p]
              CROSS APPLY p.ConfigMaster.nodes('/ConfigMaster/Components/Component/Attributes/Attribute[ contains(@PrintCode , )]') as t(u)
         ) as [m]
         Inner join @Map as s on s.Old = isnull(m.OrigValue,'')
      break --this will not exit otherwise...                 
END
select * from @ConfigMaster --after pass 3: no change

Şimdiden teşekkürler!

Clayton

Oluştur 27/11/2018 saat 18:18
kaynak kullanıcı
Diğer dillerde...                            


1 cevaplar

oy
1

Ben Bazen engelleyemiyorum ... SQL Server döngüler istemem, ancak çoğu durumda diğer yaklaşımlar ve çoğu durumda bu set bazlı yaklaşımlar iyidir vardır:

Sen uzakta onlara izin böylece beyan ad alanları gerek görünmüyor ...

Bu biraz azalır, bu nedenle tamamen ihtiyaçlarına ayak uydurmak olmayabilir. şeylerin eksik olup olmadığını bana, bildirin:

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

--ugly kaba kuvvet, ancak kolay sevimsiz-tek hat ...

UPDATE @ConfigMaster SET ConfigMaster=
REPLACE(REPLACE(REPLACE(CAST(ConfigMaster AS NVARCHAR(MAX)),' PrintCode="D"',' PrintCode="E"'),' PrintCode="3"',' PrintCode="I"'),' PrintCode=""',' PrintCode="I"');

Sınırlamalar sizin için tamam olup olmadığını --XQuery, (orada daha biri daha sonra olabilir varsayarak <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>
'); 

--ve son de bileşimi olup / yeniden bileşim (bir kaç bileşen olabilir varsayılarak)

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')
Cevap 28/11/2018 saat 20:05
kaynak kullanıcı

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more