nodes() 메서드(xml 데이터 형식)
nodes() 메서드는 xml 데이터 형식 인스턴스를 관계형 데이터로 조각으로 나눌 때 유용합니다. 이 메서드를 사용하면 새로운 행으로 매핑되는 열을 식별할 수 있습니다.
모든 xml 데이터 형식 인스턴스에는 암시적으로 제공된 컨텍스트 노드가 있습니다. 열 또는 변수에 저장된 XML 인스턴스의 경우 이 노드는 문서 노드입니다. 문서 노드는 모든 xml 데이터 형식 인스턴스의 최상위에 있는 암시적 노드입니다.
nodes() 메서드의 결과는 원래 XML 인스턴스의 논리적 복사본이 들어 있는 행 집합입니다. 이러한 논리적 복사본에서 모든 행 인스턴스의 컨텍스트 노드는 쿼리 식으로 식별된 노드 중 하나로 설정되므로 이후의 쿼리에서는 이러한 컨텍스트 노드에 따라 상대적으로 탐색할 수 있습니다.
행 집합에서 여러 값을 검색할 수 있습니다. 예를 들어 **nodes()**에 의해 반환된 행 집합에 value() 메서드를 적용하고 원래 XML 인스턴스에서 여러 값을 검색할 수 있습니다. XML 인스턴스에 적용된 경우 value() 메서드는 값을 하나만 반환합니다.
일반 구문은 다음과 같습니다.
nodes (XQuery) as Table(Column)
- XQuery
문자열 리터럴인 XQuery 식입니다. 쿼리 식이 노드를 생성하는 경우 이렇게 생성된 노드는 결과 행 집합에 제공됩니다. 쿼리 식에 의해 빈 시퀀스가 생성되는 경우 빈 행 집합이 반환됩니다. 쿼리 식이 노드 대신 원자 값이 들어 있는 시퀀스를 정적으로 생성하는 경우 정적 오류가 발생합니다.
- Table(Column)
결과 행 집합에 대한 테이블 이름 및 열 이름입니다.
예를 들어 다음과 같은 테이블을 가정해 보십시오.
T (ProductModelID int, Instructions xml)
다음 제조 지침 문서가 이 테이블에 저장되어 있고 한 조각만 표시되어 있습니다. 문서에는 3개의 제조 위치가 있습니다.
<root>
<Location LocationID="10"...>
<step>...</step>
<step>...</step>
...
</Location>
<Location LocationID="20" ...>
...
</Location>
<Location LocationID="30" ...>
...
</Location>
</root>
쿼리 식 /root/Location
에서 nodes()
메서드를 호출하면 각각 원래 XML 문서의 논리적 복사본이 들어 있고 컨텍스트 항목이 <<Location>
노드 중 하나로 설정된 3개의 행이 포함된 행 집합이 반환됩니다.
Product
ModelID Instructions
----------------------------------
1 <root>
<Location LocationID="20" ... />
<Location LocationID="30" .../></root>
1 <root><Location LocationID="10" ... />
<Location LocationID="30" .../></root>
1 <root><Location LocationID="10" ... />
<Location LocationID="20" ... />
</root>
그런 다음 xml 데이터 형식 메서드를 사용하여 이 행 집합을 쿼리할 수 있습니다. 다음 쿼리는 생성된 각 행에 대한 컨텍스트 항목의 하위 트리를 추출합니다.
SELECT T2.Loc.query('.')
FROM T
CROSS APPLY Instructions.nodes('/root/Location') as T2(Loc)
다음은 결과입니다.
ProductModelID Instructions
----------------------------------
1 <Location LocationID="10" ... />
1 <Location LocationID="20" ... />
1 <Location LocationID="30" .../>
주의
반환된 행 집합에는 유형 정보가 유지 관리됩니다. query(), value(), exist() 및 **nodes()**와 같은 xml 데이터 형식 메서드를 nodes() 메서드의 결과에 적용할 수 있습니다. 하지만 modify() 메서드를 적용하여 XML 인스턴스를 수정할 수는 없습니다.
또한 행 집합의 컨텍스트 노드는 구체화할 수 없습니다. 즉, 이 노드를 SELECT 문에서 사용할 수 없습니다. 하지만 IS NULL 및 COUNT(*)에서는 사용할 수 있습니다.
nodes() 메서드를 사용하는 방법은 OPENXML을 사용하는 방법과 동일합니다. 이 메서드는 XML에 대한 행 집합 뷰를 제공합니다. 하지만 XML 문서의 여러 행이 포함된 테이블에서 nodes() 메서드를 사용할 때는 커서를 사용할 필요가 없습니다.
nodes() 메서드에 의해 반환된 행 집합은 명명되지 않은 행 집합입니다. 따라서 별칭을 사용하여 명시적으로 이름을 지정해야 합니다.
nodes() 함수는 사용자 정의 함수의 결과에 직접 적용할 수 없습니다. 스칼라 사용자 정의 함수의 결과에서 nodes() 함수를 사용하려면 변수에 사용자 정의 함수의 결과를 할당하거나 파생 테이블을 사용하여 사용자 정의 함수 반환 값에 열 별칭을 할당한 후 CROSS APPLY를 사용하여 별칭에서 선택을 합니다.
다음 예에서는 CROSS APPLY
를 사용하여 사용자 정의 함수의 결과에서 선택하는 한 가지 방법을 보여 줍니다.
USE AdventureWorks;
GO
CREATE FUNCTION XTest()
RETURNS xml
AS
BEGIN
RETURN '<document/>';
END;
GO
SELECT A2.B.query('.')
FROM
(SELECT dbo.XTest()) AS A1(X)
CROSS APPLY X.nodes('.') A2(B);
GO
DROP FUNCTION XTest;
GO
예
1. xml 유형의 변수에 대해 nodes() 메서드 사용
다음 예에는 <Root
> 최상위 요소 하나와 <row
> 자식 요소 3개가 있는 XML 문서가 있습니다. 이 쿼리는 nodes()
메서드를 사용하여 각 <row
> 요소에 대해 하나의 개별 컨텍스트 노드를 설정합니다. nodes()
메서드는 3개의 행이 포함된 행 집합을 반환합니다. 각 행에는 원래 문서에서 서로 다른 <row
> 요소를 식별하는 각 컨텍스트 노드와 함께 원래 XML의 논리적 복사본이 들어 있습니다.
그런 다음 쿼리는 각 행에서 컨텍스트 노드를 반환합니다.
DECLARE @x xml
SET @x='<Root>
<row id="1"><name>Larry</name><oflw>some text</oflw></row>
<row id="2"><name>moe</name></row>
<row id="3" />
</Root>'
SELECT T.c.query('.') AS result
FROM @x.nodes('/Root/row') T(c)
GO
다음은 결과입니다. 이 예에서 쿼리 메서드는 컨텍스트 항목과 해당 내용을 반환합니다.
<row id="1"><name>Larry</name><oflw>some text</oflw></row>
<row id="2"><name>moe</name></row>
<row id="3"/>
컨텍스트 노드에 부모 접근자를 적용하면 3개 모두에 대한 <Root
> 요소를 반환합니다.
SELECT T.c.query('..') AS result
FROM @x.nodes('/Root/row') T(c)
go
다음은 결과입니다.
<Root>
<row id="1"><name>Larry</name><oflw>some text</oflw></row>
<row id="2"><name>moe</name></row>
<row id="3" />
</Root>
<Root>
<row id="1"><name>Larry</name><oflw>some text</oflw></row>
<row id="2"><name>moe</name></row>
<row id="3" />
</Root>
<Root>
<row id="1"><name>Larry</name><oflw>some text</oflw></row>
<row id="2"><name>moe</name></row>
<row id="3" />
</Root>
다음 쿼리는 절대 경로를 지정합니다. 절대 경로 식을 사용하는 컨텍스트 노드의 쿼리는 컨텍스트 노드의 루트 노드에서 시작합니다. 따라서 nodes()
에 의해 반환된 모든 컨텍스트 노드에 대해 3개의 행을 모두 받습니다.
SELECT T.c.query('/Root/row') AS result
FROM @x.nodes('/Root/row') T(c)
GO
<row id="1"><name>Larry</name><oflw>some text</oflw></row>
<row id="2"><name>moe</name></row>
<row id="3" />
<row id="1"><name>Larry</name><oflw>some text</oflw></row>
<row id="2"><name>moe</name></row>
<row id="3" />
<row id="1"><name>Larry</name><oflw>some text</oflw></row>
<row id="2"><name>moe</name></row>
<row id="3" />
xml 데이터 형식의 nodes()
메서드에 의해 반환된 열은 직접 사용될 수 없습니다. 예를 들어 다음 쿼리는 오류를 반환합니다.
...
SELECT T.c
FROM @x.nodes('/Root/row') T(c)
다음 쿼리에서 xml 데이터 형식의 value()
및 query()
메서드는 nodes()
메서드에 의해 반환된 행 집합에 적용됩니다. value()
메서드는 컨텍스트 항목(<row
>)의 id
특성을 반환하고 query()
메서드는 컨텍스트 항목의 <name
> 요소 하위 트리를 반환합니다.
DECLARE @x xml
SET @x='
<Root>
<row id="1"><name>Larry</name><oflw>some text</oflw></row>
<row id="2"><name>Joe</name></row>
<row id="3" />
</Root>
'
SELECT T.c.value('@id','int') as id,
T.c.query('name') as NAME
FROM @x.nodes('/Root/row') T(c)
GO
다음은 결과입니다.
id NAME
-----------------------
1 <name>Larry</name>
2 <name>Joe</name>
3
결과에는 행 ID 3
이 포함되고 <row
> 요소에는 <name
> 자식이 포함되지 않습니다. <name
> 자식 없이 행을 반환하거나 반환하지 않도록 결과를 필터링하려는 경우 다음 방식 중 하나로 필터링할 수 있습니다.
/Root/row[name]
과 같이nodes()
경로 식에 조건자를 사용합니다.- 행 집합에서 exist() 메서드를 사용합니다.
- CROSS APPLY를 사용합니다.
- OUTER APPLY를 사용합니다.
다음 쿼리는 nodes()
에 의해 반환된 행 집합에 대해 exist()
메서드를 지정합니다. exist()
메서드는 컨텍스트 노드(<row
>)에 <name
> 자식이 있는 경우 True를 반환합니다.
DECLARE @x xml
SET @x='<Root>
<row id="1"><name>Larry</name><oflw>some text</oflw></row>
<row id="2"><name>Joe</name></row>
<row id="3" />
</Root>'
SELECT T1.rows.value('@id','int') as id
FROM @x.nodes('/Root/row') T1(rows)
WHERE T1.rows.exist('name') = 1;
GO
이 쿼리는 행 ID가 1과 2인 두 행을 반환합니다.
다음 쿼리는 OUTER APPLY
를 사용합니다. OUTER APPLY
는 T1(rows)
의 각 행에 nodes()
를 적용하고 결과 집합과 NULL을 생성하는 행을 반환합니다. 따라서 WHERE 절을 사용하여 행을 필터링하고 T2.names
열이 NULL이 아닌 행만 검색합니다.
DECLARE @x xml
SET @x='
<Root>
<row id="1"><name>Larry</name><oflw>some text</oflw></row>
<row id="2"><name>Joe</name></row>
<row id="3" />
</Root>'
SELECT T1.rows.value('@id','int') as id
FROM @x.nodes('/Root/row') T1(rows)
OUTER APPLY T1.rows.nodes('./name') as T2(names)
WHERE T2.names IS NOT NULL
GO
다음 쿼리는 CROSS APPLY
를 사용합니다. CROSS APPLY
는 외부 테이블인 T1(rows)
에 있는 각 행에 nodes()
를 적용하고 nodes()
가 T1.rows
에 적용될 때 결과 집합을 생성하는 행만 반환합니다. 이 경우에는 IS NOT NULL을 테스트하는 데 WHERE 절을 사용하지 않아도 됩니다.
DECLARE @x xml
SET @x='<Root>
<row id="1"><name>Larry</name><oflw>some text</oflw></row>
<row id="2"><name>Joe</name></row>
<row id="3" />
</Root>'
SELECT T1.rows.value('@id','int') as id
FROM @x.nodes('/Root/row') T1(rows)
CROSS APPLY T1.rows.nodes('./name') as T2(names)
GO
CROSS APPLY 및 OUTER APPLY에 대한 자세한 내용은 APPLY 사용을 참조하십시오.
2. xml 유형의 열에 대해 nodes() 메서드 지정
이 예에서는 자전거 제조 지침이 사용되며 ProductModel 테이블에서 xml 유형의 Instructions 열에 저장되어 있습니다. 자세한 내용은 AdventureWorks 데이터베이스의 xml 데이터 형식 표시를 참조하십시오.
다음 예에서 nodes()
메서드는 ProductModel
테이블에 있는 xml 유형의 Instructions
열에 대해 지정됩니다.
nodes()
메서드는 /MI:root/MI:Location
경로를 지정하여 <Location
> 요소를 컨텍스트 노드로 설정합니다. 결과 행 집합에는 <Location
> 요소로 설정된 컨텍스트 노드와 함께 문서에 있는 각 <Location
> 노드에 대해 원래 문서의 논리적 복사본이 하나씩 들어 있습니다. 따라서 nodes()
함수는 일련의 <Location
> 컨텍스트 노드를 제공합니다.
이 행 집합에 대한 query()
메서드는 self::node
를 요청하므로 각 행에 <Location>
요소를 반환합니다.
이 예에서 쿼리는 특정 제품 모델의 제조 지침 문서에 각 <Location
> 요소를 컨텍스트 노드로 설정합니다. 이러한 컨텍스트 노드를 사용하여 다음과 같은 값을 검색할 수 있습니다.
- 각 <
Location
>에서 위치 ID 찾기 - 각 <
Location
>에서 제조 단계(<step
>) 검색
이 쿼리는 query()
메서드에서 self::node()
에 대한 축약형 구문 '.'
이 지정된 컨텍스트 항목을 반환합니다.
다음을 유의하십시오.
nodes()
메서드는 Instructions 열에 적용되며T (C)
행 집합을 반환합니다. 이 행 집합에는 컨텍스트 항목으로/root/Location
이 포함된 원래 제조 지침 문서의 논리적 복사본이 포함됩니다.CROSS APPLY는
Instructions
테이블의 각 행에nodes()
를 적용하고 결과 집합을 생성하는 행만 반환합니다.SELECT C.query('.') as result FROM Production.ProductModel CROSS APPLY Instructions.nodes(' declare namespace MI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"; /MI:root/MI:Location') as T(C) WHERE ProductModelID=7
다음은 결과의 일부입니다.
<MI:Location LocationID="10" ...> <MI:step ... /> ... </MI:Location> <MI:Location LocationID="20" ... > <MI:step ... /> ... </MI:Location> ...
다음 쿼리는 이전 쿼리와 비슷하지만 행 집합의 컨텍스트 노드를 사용하여 일련의 값을 검색하기 위해 value()
및 query()
를 사용합니다. 각 위치에 대해 SELECT
절은 위치 ID와 해당 위치에서 사용되는 도구를 검색합니다.
SELECT C.value('@LocationID','int') as LId,
C.query('declare namespace MI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
MI:step/MI:tool') as result
FROM Production.ProductModel
CROSS APPLY Instructions.nodes('
declare namespace MI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
/MI:root/MI:Location') as T(C)
WHERE ProductModelID=7
다음은 결과입니다. 가독성을 위해 네임스페이스는 표시되지 않았습니다.
LId result
10 <MI:tool xmlns:MI="...">T-85A framing tool</MI:tool>
<MI:tool xmlns:MI="...">Trim Jig TJ-26</MI:tool>
<MI:tool xmlns:MI="...">router with a carbide tip 15</MI:tool>
<MI:tool xmlns:MI="...">Forming Tool FT-15</MI:tool>
20
30 <MI:tool xmlns:MI="...">standard debur tool</MI:tool>
45 <MI:tool xmlns:MI="...">paint harness</MI:tool>
50
60
3. 다른 nodes() 메서드에 의해 반환된 행 집합에 nodes() 적용
다음 코드는 XML 문서에서 ProductModel
테이블의 Instructions
열에 있는 제조 지침을 쿼리합니다. 이 쿼리는 제품 모델 ID, 제조 위치 및 제조 단계가 포함된 행 집합을 반환합니다.
다음을 유의하십시오.
nodes()
메서드는Instructions
열에 적용되며T1 (Locations)
행 집합을 반환합니다. 이 행 집합에는 항목 컨텍스트로/root/Location
요소가 포함된 원래 제조 지침 문서의 논리적 복사본이 포함됩니다.nodes()
는T1 (Locations)
행 집합에 적용되며T2 (steps)
행 집합을 반환합니다. 이 행 집합에는 항목 컨텍스트로/root/Location/step
요소가 포함된 원래 제조 지침 문서의 논리적 복사본이 포함됩니다.
SELECT ProductModelID, Locations.value('./@LocationID','int') as LocID,
steps.query('.') as Step
FROM Production.ProductModel
CROSS APPLY Instructions.nodes('
declare namespace MI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
/MI:root/MI:Location') as T1(Locations)
CROSS APPLY T1.Locations.nodes('
declare namespace MI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
./MI:step ') as T2(steps)
WHERE ProductModelID=7
GO
다음은 결과입니다.
ProductModelID LocID Step
----------------------------
7 10 <step ... />
7 10 <step ... />
...
7 20 <step ... />
7 20 <step ... />
7 20 <step ... />
...
이 쿼리는 MI
접두사를 두 번 선언합니다. 대신 WITH XMLNAMESPACES
를 사용하여 접두사를 한 번만 선언하고 쿼리에서 사용할 수 있습니다.
WITH XMLNAMESPACES (
'https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions' AS MI)
SELECT ProductModelID, Locations.value('./@LocationID','int') as LocID,
steps.query('.') as Step
FROM Production.ProductModel
CROSS APPLY Instructions.nodes('
/MI:root/MI:Location') as T1(Locations)
CROSS APPLY T1.Locations.nodes('
./MI:step ') as T2(steps)
WHERE ProductModelID=7
GO
다음 쿼리는 이전 쿼리와 비슷하지만 exist()
메서드를 T2(steps)
행 집합에 있는 XML에 적용하여 적어도 하나 이상의 제조 도구를 사용하는 제조 단계만 검색합니다. 즉, <step
> 요소에는 적어도 하나 이상의 <tool
> 자식이 포함됩니다.
WITH XMLNAMESPACES (
'https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions' AS MI)
SELECT ProductModelID,
Locations.value('./@LocationID','int') as LocID,
steps.query('.') as Steps
FROM Production.ProductModel
CROSS APPLY Instructions.nodes('/MI:root/MI:Location') as T1(Locations)
CROSS APPLY T1.Locations.nodes('./MI:step') as T2(steps)
WHERE ProductModelID=7
AND steps.exist('./MI:tool') = 1
GO
참고 항목
개념
WITH XMLNAMESPACES를 사용하여 네임스페이스 추가
xml 데이터 형식
XML 인스턴스 생성
예제 XML 응용 프로그램