एक्सएमएल अनुक्रम लौटें जहां एक विशेषता में एक विशिष्ट चरित्र नहीं है


10

निम्नलिखित सरल 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>

मैं <Customer>अनुक्रमों की एक सूची प्राप्त करना चाहता हूं जहां आइटम की addressविशेषता में ए नहीं है ।<email>@

इसलिए, मुझे ऐसा आउटपुट चाहिए जो दिखता है:

<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>';

यह प्रश्न:

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

यह दिखाता है:

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

यह प्रश्न:

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

यह दिखाता है:

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

WHEREऊपर क्वेरी में खंड एक्सएमएल के पूरे सेट को नष्ट क्योंकि कम से कम एक एकल अनुक्रम मौजूद है जहां ईमेल पता एक "@" चिह्न होता है।

जवाबों:


11

एक आसान तरीका है यह करने के लिए उपयोग करने के लिए है nodes विधि का अधिकार पाने के लिए addressविशेषता है और अपने लिए चेक @पर हस्ताक्षर।

जिस तरह से आप अभी देख रहे हैं, उसके साथ समस्या यह है कि यह केवल जाँच कर रहा है कि किसी भी ईमेल पते @में यह है। XML नोड्स को पार्स करने से आप इसके लिए अलग-अलग ईमेल की जांच कर सकते हैं।

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;

यदि आपको इस तरह से XML स्तंभ के साथ एक वास्तविक तालिका को क्वेरी करने की आवश्यकता है, तो आप इस तरह से केवल CROSS APPLYनोड्स विधि:

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;

यदि आप <customer>...</customer>उस "पंक्ति" के लिए सभी XML लाना चाहते हैं , तो आप अक्ष को वापस चला सकते हैं। बस इस बात से अवगत रहें कि वापस चलना बड़े XML ब्लॉकों के लिए प्रदर्शन को थोड़ा ऊँचा बना सकता है।

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;

इसे करने का दूसरा तरीका है:

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

ईमेल नोड के चारों ओर लपेटने के लिए चौकोर कोष्ठकों को स्थानांतरित करने से प्रभावी ढंग से नोड पर लागू होने वाला WHEREखंड बन जाता है customer। इस XQuery का अंग्रेजी में अनुवाद इस तरह दिखता है:

मुझे xml/customerनोड के साथ सभी नोड्स प्राप्त करें emailजिसमें एक addressविशेषता है जिसमें @प्रतीक शामिल नहीं है


4

आप ओह इतने करीब थे। आप निश्चित रूप से .query()फ़ंक्शन का उपयोग करने और containsXQuery फ़ंक्शन का उपयोग करने के साथ सही रास्ते पर थे । आपको जो मिला वह गलत था:

  1. लाना = False बाहर का [...](जिसका अर्थ है, यह का हिस्सा नहीं था contains()अभिव्यक्ति)
  2. Falseफ़ंक्शन के बजाय शब्द का उपयोग करनाfalse()
  3. /..पथ के अंत में जोड़कर मूल नोड निर्दिष्ट न करें (ताकि परिणाम में <customer>तत्व शामिल हो और न केवल <email>तत्व शामिल हो)

निम्नलिखित XQuery अभिव्यक्ति में उन तीन चीजों को ठीक करने से परिणाम प्राप्त होता है जो आप चाहते हैं:

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

सवाल से अपने मूल उदाहरण में लाना आपको देता है:

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;

वह क्वेरी दो XML फ़ील्ड के साथ एकल पंक्ति का निम्नलिखित परिणाम सेट लौटाती है:

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()फ़ंक्शन को फ़ंक्शन के साथ तोड़ने से अधिक कुशल है क्योंकि यह एक शॉट में एक्सएमएल को पार्स कर सकता है और प्रत्येक नोड के लिए पार्सर को शुरू करने और रोकने की आवश्यकता नहीं है।

इसे अपने भीतर रखने का दूसरा लाभ यह .query()है कि आपको एक एक्सएमएल दस्तावेज लौटाया जाता है। इसलिए, यदि आपको एक XML दस्तावेज़ / मूल्य प्राप्त होता है, जिसमें कई नोड्स सामान होते हैं, तो आप परिणामी नोड्स को फिर से दस्तावेज़ में वापस लाने के बिना एकल इकाई होने के स्केलर मूल्य दृष्टिकोण को बनाए रख सकते हैं। यह भी आप इसे एक subquery / CTE में उपयोग कर सकते हैं बिना अपेक्षित पंक्तियों की संख्या को बदले।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.