Sql'deki bir dizenin XML yapısını dinamik olarak nasıl değiştirebilirim

0

Soru

Bir XML dizesini dB'den [varchar(max)] çekecek, denetleyecek ve belirli bir duruma uyuyorsa güncelleyecek bir SQL betiğine ihtiyacım var.

Xml'imin aşağıdaki biçimde olduğunu düşünün:

<root>
  <level1>
    <level2>
      <level3 />
      <level3 />
    </level2>
  </level1>
  <level1>
    <level2>
      <level3>
        <level4>
          <level5>
            <level6 here="now is the time for XYZ">
              <options>
                <option this="that" />
                <option me="you" />
              </options>
            </level6>
          </level5>
        </level4>
      </level3>
    </level2>
  </level1>
  <level1>
    <level2>
      <level3>
        <level4>
          <level5>
            <level6 here="this one is not of interest">
              <options>
                <option this="that" />
                <option me="you" />
              </options>
            </level6>
          </level5>
        </level4>
      </level3>
    </level2>
  </level1>
  <level1>
    <level2>
      <level3>
        <level4>
          <level5>
            <level6 here="now is the time for ABC">
              <options>
                <option this="that" />
                <option me="you" />
                <option here="now" />
              </options>
            </level6>
          </level5>
        </level4>
      </level3>
    </level2>
  </level1>
</root>

Yani, yapmak istediğim, adı "level6" olan ve değeri "şimdi tam zamanı" ile başlayan "burada"adlı bir özniteliğe sahip olan tüm öğeleri güncellemektir. Yani, bu sadece yukarıdaki iki öğeyle eşleşmelidir.

Ancak, tek seçim kriteri bu değil. Seçenekler listesi şunları içermemelidir <option here="now" />. Yani, bu bize güncellenecek tek bir öğe bırakmalı.

<level6 here="now is the time for XYZ">
    <options>
        <option this="that" />
        <option me="you" />
    </options>
 </level6>

Bu öğeye, eksik olanı eklemek istiyorum <option here="now" /> o yüzden bu olur:

<level6 here="now is the time for XYZ">
    <options>
        <option this="that" />
        <option me="you" />
        <option here="now" />
    </options>
 </level6>

Yani, nihai sonuç şöyle olmalıdır:

 <root>
  <level1>
    <level2>
      <level3 />
      <level3 />
    </level2>
  </level1>
  <level1>
    <level2>
      <level3>
        <level4>
          <level5>
            <level6 here="now is the time for XYZ">
              <options>
                <option this="that" />
                <option me="you" />
                <option here="now" />      // <- this one new
              </options>
            </level6>
          </level5>
        </level4>
      </level3>
    </level2>
  </level1>
  <level1>
    <level2>
      <level3>
        <level4>
          <level5>
            <level6 here="this one is not of interest">
              <options>
                <option this="that" />
                <option me="you" />
              </options>
            </level6>
          </level5>
        </level4>
      </level3>
    </level2>
  </level1>
  <level1>
    <level2>
      <level3>
        <level4>
          <level5>
            <level6 here="now is the time for ABC">
              <options>
                <option this="that" />
                <option me="you" />
                <option here="now" />
              </options>
            </level6>
          </level5>
        </level4>
      </level3>
    </level2>
  </level1>
</root>

Verileri dB'den bir dizeye okuyabildiğimi ve db'yi nasıl güncelleyeceğimi bildiğimi varsayalım, bu yüzden Sql'deki (SQL Server) xml dizesini gerçekten nasıl değiştirebilirim.

sql-server tsql xml xquery
2021-11-23 17:17:51
1

En iyi cevabı

1

XML dml'yi (veri değişikliği) şu şekilde kullanabilirsiniz: .modify xml'i değiştirme işlevi.

SET @xml.modify('
  insert <option here="now" />
  as last into
  ( /root/level1/level2/level3/level4/level5/level6
     [substring(@here, 1, 15) = "now is the time"]
     /options [not(/option[@here = "now"])]
   )[1]');

Bu aşağıdaki gibi çalışır:

  • insert <option here="now" /> bu, eklediğimiz değerdir
  • as last into seçili olanın diğer alt düğümlerinin peşinden gider
  • /root/level1/level2/level3/level4/level5/level6 bu bize şunu kazandırıyor level6 düğümlü
  • [substring(@here, 1, 15) = "now is the time"] bir düğüme sahip olmak için düğümü yükler here bu değerle başlayan öznitelik. Length parametresini karşılaştırmakta olduğunuz değerle eşleşecek şekilde değiştirmeniz gerekir. Hiç yok... LIKE xquery'de
  • /options [not(/option[@here = "now"])] aradığımız bir options olmayan düğüm option sırayla bir çocuğu olan çocuk here="now" nitelik
  • [1] bu tür ilk düğüm

Tek bir XML belgesindeki birden çok düğümü değiştirmeniz gerekirse, bunu döngüde çalıştırmanız gerekir

DECLARE @i int = 20; --max nodes

WHILE @xml.exist('
  /root/level1/level2/level3/level4/level5/level6
     [substring(@here, 1, 15) = "now is the time"]
     /options [not(option[@here = "now"])]
   ') = 1
BEGIN

    SET @xml.modify('
      insert <option here="now" /> as last into
      ( /root/level1/level2/level3/level4/level5/level6
         [substring(@here, 1, 15) = "now is the time"]
         /options [not(option[@here = "now"])]
       )[1]');
     
    SET @i -= 1;
    IF @i = 0
        BREAK;
END;

Bunu bütün bir masa için de yapabilirsiniz

DECLARE @i int = 20; --max nodes

WHILE EXISTS (SELECT 1
    FROM YourTable
    WHERE XmlColumn.exist('
      /root/level1/level2/level3/level4/level5/level6
         [substring(@here, 1, 15) = "now is the time"]
         /options [not(option[@here = "now"])]
       ') = 1)
BEGIN

    UPDATE t
    SET XmlColumn.modify('
      insert <option here="now" /> as last into
      ( /root/level1/level2/level3/level4/level5/level6
         [substring(@here, 1, 15) = "now is the time"]
         /options [not(option[@here = "now"])]
       )[1]')
    FROM YourTable t
    WHERE XmlColumn.exist('
      /root/level1/level2/level3/level4/level5/level6
         [substring(@here, 1, 15) = "now is the time"]
         /options [not(option[@here = "now"])]
       ') = 1;
     
    SET @i -= 1;
    IF @i = 0
        BREAK;
END;

Çok büyük veri kümeleri için, tüm xml'i XQuery kullanarak yeniden oluşturmak daha hızlı olabilir ve ek düğüm Yerleşik XML kullanılarak eklenir.

db < >keman<>

2021-11-23 23:41:04

Diğer dillerde

Bu sayfa diğer dillerde

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................