FLWOR 문 및 반복(XQuery)

적용 대상:SQL Server

XQuery는 FLWOR 반복 구문을 정의합니다. FLWOR는 , let, whereorder byreturn.의 for약어입니다.

FLWOR 문은 다음 부분으로 구성됩니다.

  • 하나 이상의 반복기 변수를 입력 시퀀스에 바인딩하는 하나 이상의 FOR 절입니다.

    입력 시퀀스는 XPath 식과 같은 다른 XQuery 식일 수 있습니다. 노드 시퀀스나 원자성 값의 시퀀스 중 하나입니다. 원자성 값 시퀀스는 리터럴 또는 생성자 함수를 사용하여 생성할 수 있습니다. 생성된 XML 노드는 SQL Server에서 입력 시퀀스로 허용되지 않습니다.

  • 선택적 let 절입니다. 이 절은 특정 반복에 대해 지정된 변수에 값을 할당합니다. 할당된 식은 XPath 식과 같은 XQuery 식일 수 있으며 노드 시퀀스 또는 원자성 값 시퀀스를 반환할 수 있습니다. 원자성 값 시퀀스는 리터럴 또는 생성자 함수를 사용하여 생성할 수 있습니다. 생성된 XML 노드는 SQL Server에서 입력 시퀀스로 허용되지 않습니다.

  • 반복기 변수입니다. 이 변수는 키워드를 사용하여 선택적 형식 어설션을 as 가질 수 있습니다.

  • 선택적 where 절입니다. 이 절은 반복에 필터 조건자를 적용합니다.

  • 선택적 order by 절입니다.

  • return 식입니다. return 절의 식은 FLWOR 문의 결과를 구성합니다.

예를 들어 다음 쿼리는 첫 번째 제조 위치에서 요소를 반복 <Step> 하고 노드의 <Step> 문자열 값을 반환합니다.

declare @x xml  
set @x='<ManuInstructions ProductModelID="1" ProductModelName="SomeBike" >  
<Location LocationID="L1" >  
  <Step>Manu step 1 at Loc 1</Step>  
  <Step>Manu step 2 at Loc 1</Step>  
  <Step>Manu step 3 at Loc 1</Step>  
</Location>  
<Location LocationID="L2" >  
  <Step>Manu step 1 at Loc 2</Step>  
  <Step>Manu step 2 at Loc 2</Step>  
  <Step>Manu step 3 at Loc 2</Step>  
</Location>  
</ManuInstructions>'  
SELECT @x.query('  
   for $step in /ManuInstructions/Location[1]/Step  
   return string($step)  
')  

결과는 다음과 같습니다.

Manu step 1 at Loc 1 Manu step 2 at Loc 1 Manu step 3 at Loc 1  

다음 쿼리는 ProductModel 테이블의 형식화된 xml 열인 Instructions 열에 대해 지정된다는 점을 제외하고 이전 쿼리와 비슷합니다. 쿼리는 특정 제품의 첫 번째 작업 센터 위치에서 모든 제조 단계, <step> 요소를 반복합니다.

SELECT Instructions.query('  
   declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";  
for $Step in //AWMI:root/AWMI:Location[1]/AWMI:step  
      return  
           string($Step)   
') as Result  
FROM Production.ProductModel  
where ProductModelID=7  

이전 쿼리의 다음 사항에 유의하세요.

  • $Step 반복기 변수입니다.

  • 경로 식//AWMI:root/AWMI:Location[1]/AWMI:step입력 시퀀스를 생성합니다. 이 시퀀스는 첫 번째>Location< 요소 노드의 <step> 요소 노드 자식 시퀀스입니다.

  • 조건부 절 where(옵션)는 사용되지 않습니다.

  • 식은 return 요소에서 문자열 값을 반환합니다 <step> .

문자열 함수(XQuery)는 노드의 <step> 문자열 값을 검색하는 데 사용됩니다.

다음은 부분 결과입니다.

Insert aluminum sheet MS-2341 into the T-85A framing tool.   
Attach Trim Jig TJ-26 to the upper and lower right corners of   
the aluminum sheet. ....         

허용되는 추가 입력 시퀀스의 예는 다음과 같습니다.

declare @x xml  
set @x=''  
SELECT @x.query('  
for $a in (1, 2, 3)  
  return $a')  
-- result = 1 2 3   
  
declare @x xml  
set @x=''  
SELECT @x.query('  
for $a in   
   for $b in (1, 2, 3)  
      return $b  
return $a')  
-- result = 1 2 3  
  
declare @x xml  
set @x='<ROOT><a>111</a></ROOT>'  
SELECT @x.query('  
  for $a in (xs:string( "test"), xs:double( "12" ), data(/ROOT/a ))  
  return $a')  
-- result test 12 111  

SQL Server에서는 이질적인 시퀀스를 사용할 수 없습니다. 특히 원자성 값과 노드가 혼합된 시퀀스는 허용되지 않습니다.

반복은 다음 쿼리와 같이 XML 형식을 변환하는 XML 생성 구문과 함께 자주 사용됩니다.

AdventureWorks 샘플 데이터베이스에서 Production.ProductModel 테이블의 지침 열에 저장된 제조 지침은 다음과 같은 형식입니다.

<Location LocationID="10" LaborHours="1.2"   
            SetupHours=".2" MachineHours=".1">  
  <step>describes 1st manu step</step>  
   <step>describes 2nd manu step</step>  
   ...  
</Location>  
...  

다음 쿼리는 작업 센터 위치 특성이 <Location> 자식 요소로 반환된 요소가 있는 새 XML을 생성합니다.

<Location>  
   <LocationID>10</LocationID>  
   <LaborHours>1.2</LaborHours>  
   <SetupHours>.2</SetupHours>  
   <MachineHours>.1</MachineHours>  
</Location>  
...  

다음은 쿼리입니다.

SELECT Instructions.query('  
     declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";  
        for $WC in /AWMI:root/AWMI:Location  
        return  
          <Location>  
            <LocationID> { data($WC/@LocationID) } </LocationID>  
            <LaborHours>   { data($WC/@LaborHours) }   </LaborHours>  
            <SetupHours>   { data($WC/@SetupHours) }   </SetupHours>  
            <MachineHours> { data($WC/@MachineHours) } </MachineHours>  
          </Location>  
') as Result  
FROM Production.ProductModel  
where ProductModelID=7  

이전 쿼리의 다음 사항에 유의하세요.

  • FLWOR 문은 특정 제품에 대한 요소 시 <Location> 퀀스를 검색합니다.

  • 데이터 함수(XQuery)는 각 특성의 값을 추출하는 데 사용되므로 결과 XML에 특성이 아닌 텍스트 노드로 추가됩니다.

  • RETURN 절의 식은 원하는 XML을 생성합니다.

이는 부분적인 결과입니다.

<Location>  
  <LocationID>10</LocationID>  
  <LaborHours>2.5</LaborHours>  
  <SetupHours>0.5</SetupHours>  
  <MachineHours>3</MachineHours>  
</Location>  
<Location>  
   ...  
<Location>  
...  

let 절 사용

이 절을 let 사용하여 변수를 참조하여 참조할 수 있는 반복 식의 이름을 지정할 수 있습니다. 변수에 let 할당된 식은 쿼리에서 변수를 참조할 때마다 쿼리에 삽입됩니다. 즉, 문이 식이 참조될 때마다 실행됩니다.

데이터베이스에서 AdventureWorks2022 제조 지침에는 필요한 도구 및 도구가 사용되는 위치에 대한 정보가 포함됩니다. 다음 쿼리는 절을 let 사용하여 프로덕션 모델을 빌드하는 데 필요한 도구와 각 도구가 필요한 위치를 나열합니다.

SELECT Instructions.query('  
     declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";  
        for $T in //AWMI:tool  
            let $L := //AWMI:Location[.//AWMI:tool[.=data($T)]]  
        return  
          <tool desc="{data($T)}" Locations="{data($L/@LocationID)}"/>  
') as Result  
FROM Production.ProductModel  
where ProductModelID=7  

where 절 사용

절을 where 사용하여 반복 결과를 필터링할 수 있습니다. 이 예제는 다음 예제에서 설명합니다.

자전거 제조 과정에서 제조 프로세스는 일련의 작업 센터 위치를 통과합니다. 각 작업 센터 위치는 제조 단계 시퀀스를 정의합니다. 다음 쿼리는 자전거 모델을 제조하고 제조 단계가 3개 미만인 작업 센터 위치만 검색합니다. 즉, 3개 <step> 미만의 요소가 있습니다.

SELECT Instructions.query('  
     declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";  
for $WC in /AWMI:root/AWMI:Location  
      where count($WC/AWMI:step) < 3  
      return  
          <Location >  
           { $WC/@LocationID }   
          </Location>  
') as Result  
FROM Production.ProductModel  
where ProductModelID=7  

이전 쿼리에서 다음 사항에 유의하세요.

  • 키워드는 where count() 함수를 사용하여 각 작업 센터 위치의 <step> 자식 요소 수를 계산합니다.

  • 이 식은 return 반복 결과에서 원하는 XML을 생성합니다.

결과는 다음과 같습니다.

<Location LocationID="30"/>   

절의 식 where 결과는 지정된 순서대로 다음 규칙을 사용하여 부울 값으로 변환됩니다. 정수가 허용되지 않는다는 점을 제외하고 경로 식의 조건자 규칙과 동일합니다.

  1. 식이 where 빈 시퀀스를 반환하는 경우 유효한 부울 값은 False입니다.

  2. 식이 where 하나의 단순 부울 형식 값을 반환하는 경우 해당 값은 유효 부울 값입니다.

  3. 식이 where 하나 이상의 노드를 포함하는 시퀀스를 반환하는 경우 유효 부울 값은 True입니다.

  4. 그렇지 않으면 정적 오류가 발생합니다.

FLWOR의 다중 변수 바인딩

여러 개의 변수를 입력 시퀀스에 바인딩하는 FLWOR 식을 하나만 사용할 수 있습니다. 다음 예에서는 형식화되지 않은 xml 변수에 대해 쿼리가 지정됩니다. FLOWR 식은 각><Location요소의 첫 번째 <Step> 요소 자식을 반환합니다.

declare @x xml  
set @x='<ManuInstructions ProductModelID="1" ProductModelName="SomeBike" >  
<Location LocationID="L1" >  
  <Step>Manu step 1 at Loc 1</Step>  
  <Step>Manu step 2 at Loc 1</Step>  
  <Step>Manu step 3 at Loc 1</Step>  
</Location>  
<Location LocationID="L2" >  
  <Step>Manu step 1 at Loc 2</Step>  
  <Step>Manu step 2 at Loc 2</Step>  
  <Step>Manu step 3 at Loc 2</Step>  
</Location>  
</ManuInstructions>'  
SELECT @x.query('  
   for $Loc in /ManuInstructions/Location,  
       $FirstStep in $Loc/Step[1]  
   return   
       string($FirstStep)  
')  

이전 쿼리의 다음 사항에 유의하세요.

  • 식은 for 변수를 $Loc 정의하고 $FirstStep 변수를 정의합니다.

  • 식 및 /ManuInstructions/Location$FirstStep in $Loc/Step[1]식은 two 값이 의 값 $FirstStep$Loc에 의존한다는 측면에서 상관 관계가 있습니다.

  • 연결된 $Loc 식은 요소 시 <Location> 퀀스를 생성합니다. 각 <Location> 요소 $FirstStep 에 대해 단일 <Step> 요소의 시퀀스를 생성합니다.

  • $Loc$FirstStep 변수와 관련된 식에서 지정됩니다.

결과는 다음과 같습니다.

Manu step 1 at Loc 1   
Manu step 1 at Loc 2  

다음 쿼리는 ProductModel 테이블의 Instructions 열(형식화된 xml)에 대해 지정된다는 점을 제외하고 유사합니다. XML 생성(XQuery) 은 원하는 XML을 생성하는 데 사용됩니다.

SELECT Instructions.query('  
     declare default element namespace "https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";  
for $WC in /root/Location,  
            $S  in $WC/step  
      return  
          <Step LocationID= "{$WC/@LocationID }" >  
            { $S/node() }  
          </Step>  
') as Result  
FROM  Production.ProductModel  
WHERE ProductModelID=7  

이전 쿼리에서 다음 사항에 유의하세요.

  • 절은 for 두 개의 변수를 정의하고 $S. $WC 연결된 $WC 식은 자전거 제품 모델 제조 시 작업 센터 위치 시퀀스를 생성합니다. $S 변수에 할당되는 경로 식은 $WC에 있는 각 작업 센터 위치 시퀀스에 대한 단계의 시퀀스를 생성합니다.

  • return 문은 제조 단계와 LocationID를 해당 특성으로 포함하는 요소가 있는 XML><Step을 생성합니다.

  • 기본 요소 네임스페이스 선언은 XQuery 프롤로그에서 사용되므로 결과 XML의 모든 네임스페이스 선언이 최상위 요소에 표시됩니다. 이렇게 하면 결과를 더 쉽게 읽을 수 있습니다. 기본 네임스페이스에 대한 자세한 내용은 XQuery에서 네임스페이스 처리를 참조하세요.

다음은 부분 결과입니다.

<Step xmlns=  
    "https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"     
  LocationID="10">  
     Insert <material>aluminum sheet MS-2341</material> into the <tool>T-   
     85A framing tool</tool>.   
</Step>  
...  
<Step xmlns=  
      "https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"     
    LocationID="20">  
        Assemble all frame components following blueprint   
        <blueprint>1299</blueprint>.  
</Step>  
...  

order by 절 사용

XQuery에서 정렬은 FLWOR 식의 order by 절을 사용하여 수행됩니다. 절에 order by 전달된 정렬 식은 해당 형식이 gt 연산자에 유효한 값을 반환해야 합니다. 각 정렬 식은 단일 항목이 있는 시퀀스를 생성해야 합니다. 기본적으로 정렬은 오름차순으로 수행됩니다. 필요에 따라 각 정렬 식에 대해 오름차순 또는 내림차순을 지정할 수 있습니다.

참고 항목

SQL Server의 XQuery 구현에서 수행하는 문자열 값에 대한 정렬 비교는 항상 이진 유니코드 코드포인트 데이터 정렬을 사용하여 수행됩니다.

다음 쿼리는 AdditionalContactInfo 열에서 특정 고객의 모든 전화 번호를 검색합니다. 결과는 전화 번호를 기준으로 정렬됩니다.

USE AdventureWorks2022;  
GO  
SELECT AdditionalContactInfo.query('  
   declare namespace act="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes";  
   declare namespace aci="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactInfo";  
   for $a in /aci:AdditionalContactInfo//act:telephoneNumber   
   order by $a/act:number[1] descending  
   return $a  
') As Result  
FROM Person.Person  
WHERE BusinessEntityID=291;  

Atomization(XQuery) 프로세스는 요소에 전달하기 전에 요소의><number원자성 값을 검색합니다.order by data() 함수를 사용하여 식을 작성할 수 있지만 필수는 아닙니다.

order by data($a/act:number[1]) descending  

결과는 다음과 같습니다.

<act:telephoneNumber xmlns:act="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes">  
  <act:number>333-333-3334</act:number>  
</act:telephoneNumber>  
<act:telephoneNumber xmlns:act="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes">  
  <act:number>333-333-3333</act:number>  
</act:telephoneNumber>  

쿼리 프롤로그에서 네임스페이스를 선언하는 대신 WITH XMLNAMESPACES를 사용하여 선언할 수 있습니다.

WITH XMLNAMESPACES (  
   'https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes' AS act,  
   'https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactInfo'  AS aci)  
  
SELECT AdditionalContactInfo.query('  
   for $a in /aci:AdditionalContactInfo//act:telephoneNumber   
   order by $a/act:number[1] descending  
   return $a  
') As Result  
FROM Person.Person  
WHERE BusinessEntityID=291;  

특성 값을 기준으로 정렬할 수도 있습니다. 예를 들어 다음 쿼리는 LaborHours 특성을 기준으로 정렬된 LocationID 및 LaborHours 특성이 있는 새로 만든 <Location> 요소를 내림차순으로 검색합니다. 따라서 최대 노동 시간이 있는 작업 센터 위치가 먼저 반환됩니다.

SELECT Instructions.query('  
     declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";  
for $WC in /AWMI:root/AWMI:Location   
order by $WC/@LaborHours descending  
        return  
          <Location>  
             { $WC/@LocationID }   
             { $WC/@LaborHours }   
          </Location>  
') as Result  
FROM Production.ProductModel  
WHERE ProductModelID=7;  

결과는 다음과 같습니다.

<Location LocationID="60" LaborHours="4"/>  
<Location LocationID="50" LaborHours="3"/>  
<Location LocationID="10" LaborHours="2.5"/>  
<Location LocationID="20" LaborHours="1.75"/>  
<Location LocationID="30" LaborHours="1"/>  
<Location LocationID="45" LaborHours=".5"/>  

다음 쿼리에서 결과는 요소 이름을 기준으로 정렬됩니다. 쿼리는 제품 카탈로그에서 특정 제품의 사양을 검색합니다. 사양은 요소의 자식입니다 <Specifications> .

SELECT CatalogDescription.query('  
     declare namespace  
 pd="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";  
      for $a in /pd:ProductDescription/pd:Specifications/*   
     order by local-name($a)  
      return $a  
    ') as Result  
FROM Production.ProductModel  
where ProductModelID=19;  

이전 쿼리의 다음 사항에 유의하세요.

  • 식은 /p1:ProductDescription/p1:Specifications/* .의 요소 자식을 반환합니다Specifications<>.

  • 식은 order by (local-name($a)) 요소 이름의 로컬 부분을 기준으로 시퀀스를 정렬합니다.

결과는 다음과 같습니다.

<Color>Available in most colors</Color>  
<Material>Almuminum Alloy</Material>  
<ProductLine>Mountain bike</ProductLine>  
<RiderExperience>Advanced to Professional riders</RiderExperience>  
<Style>Unisex</Style>    

순서 지정 식이 빈 상태로 반환되는 노드는 다음 예제와 같이 시퀀스의 시작 부분에 정렬됩니다.

declare @x xml  
set @x='<root>  
  <Person Name="A" />  
  <Person />  
  <Person Name="B" />  
</root>  
'  
select @x.query('  
  for $person in //Person  
  order by $person/@Name  
  return   $person  
')  

결과는 다음과 같습니다.

<Person />  
<Person Name="A" />  
<Person Name="B" />  

다음 예제와 같이 여러 정렬 조건을 지정할 수 있습니다. 이 예제의 쿼리는 먼저 제목을 기준으로 요소를 정렬한 다음 관리자 특성 값을 기준으로 요소를 정렬 <Employee> 합니다.

declare @x xml  
set @x='<root>  
  <Employee ID="10" Title="Teacher"        Gender="M" />  
  <Employee ID="15" Title="Teacher"  Gender="F" />  
  <Employee ID="5" Title="Teacher"         Gender="M" />  
  <Employee ID="11" Title="Teacher"        Gender="F" />  
  <Employee ID="8" Title="Administrator"   Gender="M" />  
  <Employee ID="4" Title="Administrator"   Gender="F" />  
  <Employee ID="3" Title="Teacher"         Gender="F" />  
  <Employee ID="125" Title="Administrator" Gender="F" /></root>'  
SELECT @x.query('for $e in /root/Employee  
order by $e/@Title ascending, $e/@Gender descending  
  
  return  
     $e  
')  

결과는 다음과 같습니다.

<Employee ID="8" Title="Administrator" Gender="M" />  
<Employee ID="4" Title="Administrator" Gender="F" />  
<Employee ID="125" Title="Administrator" Gender="F" />  
<Employee ID="10" Title="Teacher" Gender="M" />  
<Employee ID="5" Title="Teacher" Gender="M" />  
<Employee ID="11" Title="Teacher" Gender="F" />  
<Employee ID="15" Title="Teacher" Gender="F" />  
<Employee ID="3" Title="Teacher" Gender="F" />  

구현 제한 사항

제한 사항은 다음과 같습니다.

  • 정렬 식은 같은 형식이어야 합니다. 이 제한은 정적으로 확인됩니다.

  • 빈 시퀀스 정렬은 제어할 수 없습니다.

  • 비어 있는 최소, 비어 있는 최대 키워드 및 데이터 정렬 키워드는 order by 지원되지 않습니다.

참고 항목

XQuery 식