속성에 특정 문자가 포함되지 않은 XML 시퀀스를 반환


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전자 메일 주소에 "@"기호가 포함 된 경우 적어도 하나의 시퀀스가 ​​존재하기 때문에 위 쿼리 의 절은 전체 XML 세트를 제거합니다.

답변:


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()한 번에 XML을 구문 분석 할 수 있고 각 노드 당 구문 분석기를 시작 및 중지 할 필요가 없으므로 함수를 사용 하여 문서를 분류하는 것보다이 방법이 더 효율적일 수 있습니다.

이를 유지하는 또 다른 이점은 .query()단일 XML 문서가 반환된다는 것입니다. 따라서 여러 노드 가치가있는 XML 문서 / 값을 수신하는 경우 결과 노드를 다시 문서로 재구성하지 않고도 단일 엔티티 인 스칼라 값 접근법을 유지할 수 있습니다. 또한 반환되는 예상 행 수를 변경하지 않고 하위 쿼리 / CTE에서 사용할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.