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