Bir özelliğin belirli bir karakter içermediği durumlarda xml dizileri döndürme


10

Aşağıdaki basit XML'i düşünün:

<xml>
  <customer name="Max">
    <email address="me@you.com" />
  </customer>
  <customer name="Erik">
    <email address="erik@your-mom.com" />
  </customer>
  <customer name="Brent">
    <email address="brentcom" />
  </customer>
</xml>

Ben bir listesini almak istiyorum <Customer>dizilerin addressöznitelik <email>öğesi yok değil bir içerirler @.

Yani, çıktı gibi görünüyor istiyorum:

<customer name="Brent">
  <email address="brentcom" />
</customer>

mcve :

DECLARE @x XML = '<xml>
<customer name="Max"><email address="me@you.com" /></customer>
<customer name="Erik"><email address="erik@your-mom.com" /></customer>
<customer name="Brent"><email address="brentcom" /></customer>
</xml>';

Bu sorgu:

SELECT WithValidEmail = @x.query('/xml/customer/email[contains(@address, "@")]')
    , WithInvalidEmail = @x.query('/xml/customer/email[contains(@address, "@")] = False');

İadeler:

╔═══════════════════════════════════════╦══════════════════╗
            WithValidEmail              WithInvalidEmail 
╠═══════════════════════════════════════╬══════════════════╣
 <email address="me@you.com" />                          
 <email address="erik@your-mom.com" />  false            
╚═══════════════════════════════════════╩══════════════════╝

Bu sorgu:

SELECT WithInValidEmail = @x.query('/xml/customer/email')
WHERE @x.exist('/xml/customer/email[contains(@address, "@")]') = 0;

İadeler:

╔══════════════════╗
 WithInValidEmail 
╚══════════════════╝
    (no results)

WHEREE-posta adresi "@" işareti içeriyor nerede en azından tek bir dizi var çünkü yukarıdaki sorguda fıkra XML kümesinin tamamını ortadan kaldırılmasıdır.

Yanıtlar:


11

Bunu yapmanın kolay bir yolu , özniteliğe doğrudan ulaşmak ve işaretinizi kontrol etmek için nodes yöntemi kullanmaktır .address@

Şimdi arama şeklinizle ilgili sorun, yalnızca herhangi bir e-posta adresinin içinde olup olmadığını kontrol etmesidir @. XML düğümlerini ayrıştırma, e-postaları tek tek kontrol etmenizi sağlar.

DECLARE @x XML
    = '<xml>
<customer name="Max"><email address="me@you.com" /></customer>
<customer name="Erik"><email address="erik@your-mom.com" /></customer>
<customer name="Brent"><email address="brentcom" /></customer>
</xml>';


SELECT x.c.value('@address', 'VARCHAR(100)') AS [email]
FROM   @x.nodes('/xml/customer/email') AS x(c)
WHERE  x.c.exist('@address[contains(., "@")]') = 0;

Gerçek bir tabloyu böyle bir XML sütunuyla sorgulamanız gerekiyorsa, yalnızca CROSS APPLYbu şekilde nodes yöntemini kullanırsınız:

SELECT x.c.value('@address', 'VARCHAR(100)') AS [email]
FROM @x_table AS xt
CROSS APPLY xt.x.nodes('/xml/customer/email') AS x(c)
WHERE  x.c.exist('@address[contains(., "@")]') = 0;

Bu <customer>...</customer>"satır" için tüm XML'leri geri getirmek isterseniz , ekseni geri yürütebilirsiniz. Sadece geri çekilmenin büyük XML blokları için performansı biraz woogy yapabileceğini unutmayın.

SELECT x.c.query('..')
FROM @x_table AS xt
CROSS APPLY xt.x.nodes('/xml/customer/email') AS x(c)
WHERE  x.c.exist('@address[contains(., "@")]') = 0;

Bunu yapmanın başka bir yolu:

SELECT @x.query('/xml/customer[email/@address[not(contains(., "@"))]]') answer

Köşeli parantezleri e-posta düğümü etrafına sarmak için hareket ettirmek, bu WHEREcümlenin customerdüğüme uygulanmasını sağlar . Bu XQuery'yi İngilizce'ye çevirmek şöyle görünür:

Sembolü içermeyen bir özniteliğe xml/customersahip bir emaildüğüme sahip tüm düğümleri aladdress@


4

Çok yakındın. .query()İşlevi ve containsXQuery işlevini kullanarak kesinlikle doğru yoldasınız . Yanlış yaptığınız şey:

  1. Koyarak = False dışında bir [...](anlam, bu parçası değildi contains()ifadesi)
  2. Falseİşlevi yerine sözcüğü kullanmafalse()
  3. /..Yolun sonuna ekleyerek üst düğümü belirtmeme (sonuç <customer>yalnızca <email>öğeyi değil öğeyi içerecek şekilde )

Bu üç şeyi düzeltmek, size istediğinizi sağlayan aşağıdaki XQuery ifadesiyle sonuçlanır:

'/xml/customer/email[contains(@address, "@") = false()]/..'

Bunu sorudan orijinal örneğinize koymak size şunları verir:

DECLARE @x XML = '<xml>
<customer name="Max"><email address="me@you.com" /></customer>
<customer name="Erik"><email address="erik@your-mom.com" /></customer>
<customer name="Brent"><email address="brentcom" /></customer>
</xml>';

SELECT
@x.query('/xml/customer/email[contains(@address, "@")]/..') AS [WithValidEmail],
@x.query('/xml/customer/email[contains(@address, "@")=false()]/..') AS [WithInvalidEmail;

Bu sorgu, iki XML alanına sahip tek bir satırın aşağıdaki sonuç kümesini döndürür:

WithValidEmail                            |     WithInvalidEmail
<customer name="Max">                     |     <customer name="Brent">
  <email address="me@you.com" />          |       <email address="brentcom" />
</customer>                               |     </customer>
<customer name="Erik">                    |
  <email address="erik@your-mom.com" />   |
</customer>                               |

.nodes()XML'i tek bir çekimde ayrıştırabildiği ve her düğüm için ayrıştırıcıyı başlatması ve durdurması gerekmediğinden , bu muhtemelen belgeyi işlevle dağıtmaktan daha etkilidir .

İçinde tutmanın bir diğer yararı .query()da tek bir XML belgesi döndürmenizdir. Bu nedenle, değerinde birden çok düğüm içeren bir XML belgesi / değeri alırsanız, elde edilen düğümleri tekrar bir belgeye yeniden yapılandırmak zorunda kalmadan tek bir varlık olarak skaler değer yaklaşımını koruyabilirsiniz. Bu ayrıca, döndürülen beklenen satır sayısını değiştirmeden bir alt sorguda / CTE'de kullanmanızı sağlar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.