XQuery 및 정적 형식 지정
SQL Server의 XQuery는 정적으로 형식화된 언어입니다. 즉 특정 함수나 연산자에서 허용하지 않는 형식이나 카디널리티가 있는 값을 식에서 반환하면 쿼리를 컴파일하는 동안 유형 오류가 발생합니다. 또한 정적 형식 확인을 통해 형식화된 XML 문서의 경로 식의 형식이 잘못 지정되었는지 여부도 검색할 수 있습니다. XQuery 컴파일러는 먼저 원자화와 같은 암시적 연산을 추가한 다음 정적 형식 유추와 정적 형식 확인을 수행하는 정규화 단계를 적용합니다.
정적 형식 유추
정적 형식 유추를 통해 식의 반환 형식이 결정됩니다. 즉, 입력 매개 변수의 정적 형식과 연산의 정적 의미 체계를 사용하고 해당 결과에 대한 정적 형식을 유추하여 결정됩니다. 예를 들어 식 1 + 2.3의 정적 형식은 다음과 같은 방법으로 결정됩니다.
- 1의 정적 형식은 xs:integer이고 2.3의 정적 형식은 xs:decimal입니다. 동적 의미 체계를 기준으로 하는 + 연산의 정적 의미 체계는 정수를 10진수로 변환한 다음 10진수를 반환합니다. 그러면 유추되는 정적 형식은 xs:decimal이 됩니다.
형식화되지 않은 XML 인스턴스의 경우 해당 데이터가 형식화되지 않았음을 나타내는 특수한 형식이 있습니다. 이 정보는 정적 형식을 확인하는 동안 특정한 암시적 캐스트를 수행하는 데 사용됩니다.
형식화된 데이터의 입력 형식은 XML 데이터 유형 인스턴스를 제한하는 XML 스키마 컬렉션에서 유추됩니다. 예를 들어 스키마에서 xs:integer 형식의 요소만 허용하는 경우 이러한 요소를 사용하는 경로 식의 결과는 형식이 xs:integer인 0개 이상의 요소가 됩니다. 이것은 현재 element(age,xs:integer)*와 같은 식을 사용하여 표현됩니다. 여기서 별표(*)는 결과 형식의 카디널리티를 나타냅니다. 이 예에서 식 결과는 이름이 "age"이고 형식은 xs:integer인 0개 이상의 요소가 될 수 있습니다. 기타 카디널리티로서 1은 형식 이름만을 사용하여 표현되고 0 또는 1은 물음표(?)를 사용하여 표현되며 1 이상은 더하기 부호(+)를 사용하여 표현됩니다.
때때로 정적 형식 유추를 통해 식이 항상 빈 시퀀스를 반환할 것이라고 유추할 수 있습니다. 예를 들어 형식화된 XML 데이터 유형의 경로 식은 <customer> 요소(/customer/name) 내에서 <name> 요소를 찾지만 스키마가 <customer> 내에서 <name>을 허용하지 않는 경우 정적 형식 유추를 통해 결과가 비어 있을 것이라고 유추합니다. 이것은 잘못된 쿼리를 검색하는 데 사용되며 식이 ()나 data( () )가 아니면 정적 오류로 보고됩니다.
상세한 유추 규칙은 XQuery 사양의 정식 의미 체계에 제공되어 있습니다. Microsoft에서는 형식화된 XML 데이터 유형 인스턴스와 작동하도록 이러한 규칙을 약간 수정했습니다. 기존의 내용과 가장 많이 다른 점은 암시적 문서 노드에서 XML 데이터 유형 인스턴스의 형식에 대해 인식한다는 점입니다. 따라서 /age 형식의 경로 식은 이 정보에 따라 정확하게 입력됩니다.
SQL Server 프로파일러 사용를 사용하면 쿼리 컴파일의 일부로 반환된 정적 형식을 볼 수 있습니다. 이러한 정적 형식을 보려면 TSQL 이벤트 범주에 있는 XQuery Static Type 이벤트가 추적에 포함되어야 합니다.
정적 형식 확인
정적 형식 확인을 통해 런타임 실행으로 해당 연산에 적합한 형식의 값만을 받도록 합니다. 런타임 시에는 형식을 확인할 필요가 없으므로 컴파일 초기에 잠재적인 오류를 검색할 수 있습니다. 따라서 성능 향상에 도움이 됩니다. 그러나 정적 형식 지정의 경우 쿼리 작성자가 보다 주의해서 쿼리를 구성해야 합니다.
다음은 사용할 수 있는 적합한 형식입니다.
함수나 연산에서 명시적으로 허용된 형식
명시적으로 허용된 형식의 하위 유형
하위 유형은 XML 스키마의 제한이나 확장을 통해 파생을 사용하기 위한 하위 유형 지정 규칙에 따라 정의됩니다. 예를 들어 형식 S의 모든 값이 형식 T의 인스턴스라면 형식 S는 형식 T의 하위 유형입니다.
또한 XML 스키마 형식 계층에 따라 모든 정수 값은 10진수 값도 됩니다. 그러나 모든 10진수 값이 정수는 아닙니다. 따라서 정수는 10진수의 하위 유형이지만 10진수는 정수의 하위 유형이 아닙니다. 예를 들어 + 연산은 xs:integer, xs:decimal, xs:float 및 xs:double 등의 숫자 형식과 같은 특정 유형의 값만 허용합니다. xs:string과 같은 다른 형식의 값이 전달되면 연산에서 유형 오류가 발생합니다. 이를 강한 형식 지정이라고 합니다. 형식화되지 않은 XML을 나타내는 데 사용되는 원자성 유형과 같은 다른 형식의 값은 해당 연산에서 허용하는 형식의 값으로 암시적으로 변환될 수 있습니다. 이를 약한 형식 지정이라고 합니다.
암시적 변환 이후에 약한 형식 지정이 필요한 경우 정적 형식 확인을 통해 올바른 카디널리티를 가진 허용되는 형식의 값만 연산으로 전달되도록 합니다. "string" + 1의 경우 "string"의 정적 형식은 xs:string으로 인식됩니다. 이 형식은 + 연산에 허용되는 형식이 아니므로 유형 오류가 발생합니다.
임의의 식 E1의 결과를 임의의 식 E2(E1 + E2)에 추가하는 경우 정적 형식 유추를 통해 먼저 E1과 E2의 정적 형식을 확인한 다음 이러한 정적 형식을 해당 연산에 허용되는 형식과 대조합니다. 예를 들어 E1의 정적 형식이 xs:string이나 xs:integer가 될 수 있다면 런타임 시 일부 값이 정수가 될 수 있는 경우에도 정적 형식 확인을 통해 유형 오류가 발생합니다. E1의 정적 형식이 **xs:integer***인 경우에도 마찬가지입니다. + 연산에서는 정확히 정수 값 1만 허용하고 E1은 0이나 1보다 큰 수만 반환할 수 있으므로 정적 형식 확인을 통해 오류가 발생합니다.
앞에서도 설명한 대로 형식 유추를 통해 전달될 데이터의 형식에 대해 사용자가 알고 있는 것보다 폭넓은 형식을 유추하기도 합니다. 이러한 경우 사용자는 쿼리를 다시 작성해야 합니다. 그러한 경우를 몇 가지 예로 들면 다음과 같습니다.
형식은 상위 형식이나 형식의 결합 같은 좀더 광범위한 형식을 유추합니다. 형식이 원자성 유형인 경우 실제 정적 형식을 나타낼 때 캐스트 식이나 생성자 함수를 사용해야 합니다. 예를 들어 식 E1의 유추된 형식을 xs:string 또는 xs:integer 중에서 선택할 수 있고 더하기 연산에 xs:integer가 필요한 경우 E1+E2 대신 xs:integer(E1) + E2를 작성해야 합니다. 이 식은 xs:integer로 캐스팅될 수 없는 문자열 값이 있는 경우 런타임 시 실패할 수 있습니다. 그러나 현재 이 식은 정적 형식 확인을 통과합니다. SQL Server 2005부터 이 식은 빈 시퀀스로 매핑됩니다.
형식이 실제로 데이터에 있는 것보다 상위의 카디널리티를 유추합니다. xml 데이터 유형이 최상위 요소를 둘 이상 포함할 수 있고 XML 스키마 컬렉션에서 이를 제한할 수 없기 때문에 종종 이러한 문제가 발생합니다. 정적 형식을 줄이고 최대 하나의 값만 전달되도록 하려면 위치 조건자 [1]을 사용해야 합니다. 예를 들어 최상위 요소 아래에 있는 b 요소의 c 특성에 대한 값에 1을 추가하려면 write (/a/b/@c)[1]+1을 수행해야 합니다. 또한 DOCUMENT 키워드를 XML 스키마 컬렉션과 함께 사용할 수 있습니다.
일부 연산에서는 유추하는 동안 형식 정보가 손실됩니다. 예를 들어 노드 유형을 확인할 수 없는 경우 anyType이 됩니다. 이 유형은 다른 유형으로 암시적으로 캐스팅되지 않습니다. 이러한 변환은 부모 축을 사용하여 특히 탐색 중에 발생합니다. 식에서 정적 형식 오류가 발생하는 경우 이러한 연산을 사용하지 않고 쿼리를 다시 작성해야 합니다.
UNION 유형에 대한 유형 검사
UNION 유형은 유형 검사로 인해 조심스럽게 처리해야 합니다. 다음 예에서는 두 가지 문제에 대해 설명합니다.
예: UNION 유형에 대한 함수
UNION 유형의 <r>에 대한 요소 정의를 고려하십시오.
<xs:element name="r">
<xs:simpleType>
<xs:union memberTypes="xs:int xs:float xs:double"/>
</xs:simpleType>
</xs:element>
XQuery 컨텍스트 내에서 "평균" 함수인 fn:avg (//r)는 XQuery 컴파일러에서 fn:avg() 인수에 있는 <r> 요소에 대해 다른 유형(xs:int, xs:float 또는 xs:double)의 값을 추가할 수 없기 때문에 정적 오류를 반환합니다. 이 문제를 해결하려면 함수 호출을 fn:avg(for $r in //r return $r cast as xs:double ?)로 다시 작성합니다.
예: UNION 유형에 대한 연산자
더하기 연산('+')에는 정확한 유형의 피연산자가 필요합니다. 따라서 (//r)[1] + 1 식은 <r> 요소에 대해 앞에서 설명한 유형 정의가 있는 정적 오류를 반환합니다. 한 가지 해결 방법은 식을 (//r)[1] cast as xs:int? +1(여기서 "?"는 0 또는 1 발생 횟수를 나타냄)로 다시 작성하는 것입니다. 모든 캐스트는 런타임 오류의 결과로 빈 시퀀스를 발생시킬 수 있기 때문에 SQL Server 2005부터 SQL Server에는 "cast as"와 "?"가 필요합니다.