 |  |
|
난이도 : 중급 Matthias Nicola, DB2/XML Performance, IBM Silicon Valley Laboratory Vitor Rodrigues, DB2 pureXML Technical Enablement, IBM
2007 년 10 월 30 일 DB2® pureXML™은 XML 데이터를 위한 계층적 스토리지와 SQL/XML과 XQuery 같은 고급 XML 쿼리 기능을 제공합니다. SQL/XML은 SQL 언어의 표준 확장이기 때문에, XQuery 또는 XPath는 SQL에 삽입될 수 있습니다. 이는 XML과 관계형 데이터의 통합 프로세싱에 적용되거나, 다른 것으로의 전환에 적용됩니다. SQL/XML에서 가장 다재 다능한 기능은 XMLTABLE입니다. 본 시리즈 Part 1에서는, XMLTABLE을 사용하여 관계형 포맷에서 XML 데이터를 검색하는 방법을 배웁니다. 반복되거나 소실된 XML 엘리먼트를 관리하는 방법과, XMLTABLE 함수에서 네임스페이스를 핸들하는 방법을 배웁니다. Part 2에서는 XML shredding 같은 일반적인 XMLTABLE 사용 시나리오, 대형 문서를 작은 문서들로 나누기, XML 데이터를 통한 관계형 뷰를 설명합니다.
XMLTABLE 개요
이 글을 이해하려면, DB2에서 pureXML 지원과 DB2에서 XML 데이터를 쿼리하는 기초에 익숙해져야 한다. 이러한 주제들이 익숙하지 않다면, 참고자료 섹션을 참조하라.
XMLTABLE은 XQuery 식을 계산하고 결과를 관계형 테이블로서 리턴하는 SQL/XML 함수이다. XQuery 식이 XML 노드의 시퀀스를 리턴하지만, XMLTABLE은 이 시퀀스를 관계형 포맷의 행 세트로서 리턴한다. 리턴된 테이블에는 XML 유형을 포함하여, SQL 유형의 컬럼들이 포함될 수 있다.
그림 1. XMLTABLE 개요
여느 SQL/XML 함수처럼, XMLTABLE은 SQL 문에 삽입된다. XMLTABLE 함수의 계산은 rowset을 리턴하는데, 각 컬럼은 SQL 데이터 유형을 갖고 있다. 이것은 테이블 함수이지 스칼라 함수가 아니다.
XMLTABLE 함수에 대해 보다 자세히 배우려면, 다음의 샘플 테이블을 보라. 두 개의 행과 행 당 하나의 XML 문서가 포함되어 있다.
표 1: 샘플 테이블과 데이터
| table emp (doc XML) 생성하기; |
<dept bldg="101">
<employee id="901">
<name>
<first>John</first>
<last>Doe</last>
</name>
<office>344</office>
<salary currency="USD">55000</salary>
</employee>
<employee id="902">
<name>
<first>Peter</first>
<last>Pan</last>
</name>
<office>216</office>
<phone>905-416-5004</phone>
</employee>
</dept>
|
|
<dept bldg="114">
<employee id="903">
<name>
<first>Mary</first>
<last>Jones</last>
</name>
<office>415</office>
<phone>905-403-6112</phone>
<phone>647-504-4546</phone>
<salary currency="USD">64000</salary>
</employee>
</dept>
|
|
Listing 1은 간단한 XMLTABLE 문의 예이다.
Listing 1. XMLTABLE 문
SELECT X.*
FROM emp,
XMLTABLE ('$d/dept/employee' passing doc as "d"
COLUMNS
empID INTEGER PATH '@id',
firstname VARCHAR(20) PATH 'name/first',
lastname VARCHAR(25) PATH 'name/last') AS X
|
이 쿼리를 DB2에서 실행하면 다음과 같은 결과를 리턴한다.
empID firstname lastname
----------- -------------------- -------------------------
901 John Doe
902 Peter Pan
903 Mary Jones
|
이것이 어떻게 작동했는지 궁금하다. XMLTABLE 함수는 SELECT 문의 FROM 구문과 emp 테이블에서 사용된다. XMLTABLE 함수는 테이블 emp와 결합되고 각 행에 적용된다.
XMLTABLE 함수에는 한 개의 행-생성(row-generating) XQuery 식이 포함되고, COLUMNS 문에는, 한 개 또는 다중 컬럼-생성(column-generating) 식이 포함된다. Listing 1에서, 행-생성 식은 XPath $d/dept/employee이다. passing 문은 변수 $d가 테이블 emp의 XML 컬럼 doc를 의미한다는 것을 정의하고 있다.
행-생성 식은 XML 컬럼에 있는 각 XML 문서에 적용되고 문서당 한 개 또는 다중 employee 엘리먼트(하위 트리)를 만들어 낸다. XMLTABLE 함수의 아웃풋에는 각 employee 엘리먼트 당 한 행을 포함하고 있다. 따라서, 행-생성 XQuery 식에서 생성된 아웃풋은 SELECT 문의 결과 세트의 카디널리티(cardinality)를 결정한다.
COLUMNS 문은 XML 데이터를 관계형 데이터로 변형하는데 사용된다. 이 문의 각 엔트리들은 컬럼 이름과 SQL 데이터 유형을 가진 컬럼을 정의한다. 위 예제에서, 리턴된 행들은 empID, firstname, lastname이라고 하는 세 개의 컬럼을 갖고 있고 각각 데이터 유형이 Integer, Varchar(20), Varchar(25)이다. 각 컬럼의 값들은 employee 엘리먼트에서 추출되었으며, 이들은 행-생성 XQuery 식에서 생성되어, SQL 데이터 유형으로 던져진다. 예를 들어, name/first 경로는 각 employee 엘리먼트에 적용되어 firstname 컬럼에 대한 값을 획득한다. 행-생성 식은 컬럼-생성 식에 대한 콘텍스트를 제공한다. 다시 말해서, 컬럼-생성 식을 행-생성 식에 붙여서 주어진 XMLTABLE 함수가 컬럼에 무엇을 리턴하는지를 파악한다.
COLUMNS 구문의 경로 식들은 행 당 한 개 이상의 아이템을 리턴해서는 안된다. 경로 식이 두 개 이상의 아이템들의 시퀀스를 리턴하면, XMLTABLE 실행은 실패한다. XML 값 시퀀스를 원자 SQL 값으로 변환할 수 없기 때문이다. 이 시나리오는 이 글 후반에 설명하겠다.
XMLTABLE 쿼리의 결과 세트는 SQL 테이블처럼 취급될 수 있다. 정식 rowset 또는 view를 사용하는 것처럼 이것을 쿼리 및 조작할 수 있다. "passing column as" 구문을 사용하는 대신, db2-fn:xmlcolumn() 또는 db2-fn:sqlquery() 함수 (DB2 LUW 전용)를 사용하여 XMLTABLE 함수에 대한 데이터 인풋을 지정할 수 있다. 예를 들어, Listing 1은 Listing 2처럼 작성되어 같은 결과를 만들어 낸다.
Listing 2. Listing 1의 다른 표현법
SELECT X.*
FROM
XMLTABLE ('db2-fn:xmlcolumn("EMP.DOC")/dept/employee'
COLUMNS
empID INTEGER PATH '@id',
firstname VARCHAR(20) PATH 'name/first',
lastname VARCHAR(25) PATH 'name/last') AS X
|
소실 엘리먼트
XML 데이터에는 모든 문서에 나타나지 않는 선택적 엘리먼트들이 포함될 수 있다. 예를 들어, 표 1에서, employee Peter Pan은 salary 엘리먼트를 갖고 있지 않다. 이것이 샘플 시나리오에서 필수적인 데이터 필드가 아니기 때문이다. XMLTABLE 함수는 소실 엘리먼트에 대해 무효 값을 만들어내기 때문에 다루기 쉽다. 따라서 여러분은 salary 엘리먼트가 늘 있는 것처럼 XMLTABLE 쿼리를 작성할 수 있다. (Listing 3)
Listing 3. salary 컬럼을 만들어 내는 Listing 1의 확장
SELECT X.*
FROM emp,
XMLTABLE ('$d/dept/employee' passing doc as "d"
COLUMNS
empID INTEGER PATH '@id',
firstname VARCHAR(20) PATH 'name/first',
lastname VARCHAR(25) PATH 'name/last',
salary INTEGER PATH 'salary') AS X
|
이 쿼리는 다음과 같은 값을 리턴하는데, 리턴된 관계형 테이블에서 salary 컬럼은 employee Peter Pan에 대한 무효 값을 갖고 있다.
empID firstname lastname salary
----------- -------------------- ------------------- ----------
901 John Doe 55000
902 Peter Pan -
903 Mary Jones 64000
|
"무효"가 아닌 다른 값이 소실 엘리먼트에 나타나게 하려면(이를 테면, 0), 예상 엘리먼트가 소실될 경우 리턴되는 기본 값을 정의할 수 있다. Listing 4에서, Peter Pan에 대한 salary는 "0"으로 리턴된다. 기본 값은 컬럼의 대상 데이터 유형과 매치해야 한다. "salary"는 정수 컬럼에 매핑되므로, 기본 값은 정수가 되어야 한다.
Listing 4. salary에 대한 컬럼-생성 식에 기본 값 사용하기
SELECT X.*
FROM emp,
XMLTABLE ('$d/dept/employee' passing doc as "d"
COLUMNS
empID INTEGER PATH '@id',
firstname VARCHAR(20) PATH 'name/first',
lastname VARCHAR(25) PATH 'name/last',
salary INTEGER default 0 PATH 'salary') AS X
|
데이터의 하위 세트에 대한 행 생성하기
일부 필터링 술어에 기반하여 employee들의 하위 세트에 대한 행들만 만들어야 할 경우가 있다. 쉬운 솔루션은 WHERE 문과 XMLEXISTS 술어를 쿼리에 추가하는 것이다. (참고자료) 또 다른 솔루션은 XMLTABLE 함수의 행-생성 식에 필터링 술어를 사용하는 것이다. building 114에 있는 employee에 대한 행들을 만들어야 하는 경우를 생각해 보자. building 114의 유일한 사원인 Mary Jones에 대한 단 한 행만을 리턴하는 쿼리에 상응하는 술어를 추가할 수 있다. Listing 5는 행-필터링 술어를 Listing 1에 추가하는 법을 설명하고 있다.
Listing 5. Listing 1에 행 필터링 술어 추가하기
SELECT X.*
FROM emp,
XMLTABLE ('$d/dept[@bldg="114"]/employee' passing doc as "d"
COLUMNS
empID INTEGER PATH '@id',
firstname VARCHAR(20) PATH 'name/first',
lastname VARCHAR(25) PATH 'name/last',
salary INTEGER default 0 PATH 'salary') AS X
|
셀 당 다중 값 핸들링 하기
앞서 언급했던 것처럼, COLUMNS 문의 경로 식은 행 당 한 개 이상의 아이템을 만들어 내서는 안된다. 표 1의 샘플 문서에서, employee Mary Jones는 두 개의 전화 번호를 갖고 있다. 이 데이터를 쿼리하고 이름과 전화 번호를 가진 관계형 테이블을 리턴하려면 쿼리는 다음과 같이 작성되어야 한다.
Listing 6. XML 데이터를 관계형으로 추출하기
SELECT X.* FROM emp ,
XMLTABLE ('$d/dept/employee' passing doc as "d"
COLUMNS
first VARCHAR(25) PATH 'name/first',
last VARCHAR(25) PATH 'name/last',
phone VARCHAR(12) PATH 'phone' ) AS X
|
이 글에 사용되는 샘플 문의 경우, 이 쿼리는 실패한다. 다음과 같은 에러 메시지를 만들어 낸다.
SQL16003N An expression of data type "( item(), item()+ )" cannot be used when the data type "VARCHAR_12" is expected in the context.
이 메시지는 쿼리가 여러 아이템의 XML 시퀀스를 하나의 Varchar 값에 던지기를 시도했다는 의미이다. 데이터 유형 "(item(), item()+)"의 값은 이 값이 하나의 아이템이고 여기에 한 개 이상의 추가 아이템이 뒤따른다는 것을 의미한다. 간단히 말해서, 이 값은 두 개 이상의 아이템들의 시퀀스이다. 경로 식 "phone"이 employee Mary Jones에 대해 두 개의 전화 번호를 리턴하기 때문에 이 같은 일이 발생한다.
이러한 에러를 피하는데 도움이 되는 다섯 가지 옵션은 다음과 같다. 이러한 각 옵션들은 고유의 장점을 갖고 있기 때문에, 필요에 맞게 사용하면 된다.
여러 엘리먼트에서 단 한 개만 리턴한다.
이러한 문제를 다루는 한 가지 방법은 여러 전화 번호들 중에서 단 하나만 리턴하는 것이다. 각 사원에 대한 요약된 정보가 필요하다면, 단 하나의 전화 번호로도 충분하다. 단 한 개의 전화 번호만 리턴하기는 컬럼 phone용 XPath 식에 위치 술어를 사용한다. (Listing 7)
Listing 7. 각 사원에 대해 첫 번째 전화 엘리먼트만 리턴하기
SELECT X.* FROM emp ,
XMLTABLE ('$d/dept/employee' passing doc as "d"
COLUMNS
first VARCHAR(25) PATH 'name/first',
last VARCHAR(25) PATH 'name/last',
phone VARCHAR(12) PATH 'phone[1]'
) AS X
|
XPath에서 대괄호 []는 술어를 지정하는데 사용된다. 사원에 대한 첫 번째 전화 번호 엘리먼트를 얻으려면, [1] 또는 [fn:position()=1]로 작성된 위치 술어를 사용한다. 전자의 [1]은 후자를 축약한 것이다. Listing 7은 다음과 같은 결과 세트를 리턴한다.
first last phone
------------------------- ------------------------- ------------
John Doe -
Peter Pan 905-416-5004
Mary Jones 905-403-6112
3 record(s) selected.
|
하나의 Varchar에 여러 값들의 리스트를 리턴하기
모든 전화 번호를 리턴해야 한다면, 하나의 컬럼 안에 이들을 리스팅 할 수 있다. VARCHAR(12)는 여러 전화 번호에는 너무 작기 때문에, 리턴된 컬럼에 대한 SQL 유형이 변경되어야 한다. 여기에서는 VARCHAR(100)을 사용하는데, 콤마로 분리된 여러 전화 번호들을 만들어 낼 수 있다. (Listing 8)
Listing 8. 한 명의 사원에 대한 모든 전화 번호 리스팅 하기
SELECT X.* FROM emp ,
XMLTABLE ('$d/dept/employee' passing doc as "d"
COLUMNS
first VARCHAR(25) PATH 'name/first',
last VARCHAR(25) PATH 'name/last',
phone VARCHAR(100) PATH 'fn:string-join(phone/text(),",")'
) AS X
|
샘플 데이터의 경우, 이 쿼리는 다음을 리턴한다.
first last phone
------------ -------------- -------------------------
John Doe
Peter Pan 905-416-5004
Mary Jones 905-403-6112,647-504-4546
3 record(s) selected.
|
phone 컬럼에는 employee Mary Jones에 대한 두 개의 전화 번호가 포함되어 있다. fn:string-join은 이러한 값들을 연결하고 두 개의 매개변수를 필요로 한다. 스트링 값의 시퀀스와 분류자 문자이다. 이 예제에서, 이 두 개의 매개변수들은 전화 번호 엘리먼트의 텍스트 노드의 시퀀스와 "," 문자가 된다.
여러 엘리먼트들을 XML 시퀀스로서 리턴한다.
한 명의 사원에 대해 여러 전화 번호들을 리턴하는 또 다른 옵션은 XML 시퀀스의 전화 번호 엘리먼트를 리턴하는 것이다. (Listing 9) 이를 위해서, 생성된 전화 번호 컬럼은 XML 유형이 되어야 하고, 이는 XPath 식의 결과로서 어떤 XML 값도 리턴할 수 있다. 이 값은 원자 값 또는 시퀀스가 될 수 있다.
Listing 9. 모든 전화 엘리먼트들을 XML 시퀀스로서 리턴하기
SELECT X.* FROM emp ,
XMLTABLE ('$d/dept/employee' passing doc as "d"
COLUMNS
first VARCHAR(5) PATH 'name/first',
last VARCHAR(5) PATH 'name/last',
phone XML PATH 'phone'
) AS X
|
이 쿼리는 XML 컬럼 phone에 XML 시퀀스로 된 전화 번호들이 있는 employee 행 하나를 리턴한다.
first last phone
----- ----- --------------------------------------------------------
John Doe -
Peter Pan <phone>905-416-5004</phone>
Mary Jones <phone>905-403-6112</phone><phone>647-504-4546</phone>
3 record(s) selected.
|
Mary Jones에 대한 phone 컬럼에 리턴된 XML 값은 잘 구성된 XML 문서는 아니다. 하나의 루트 엘리먼트가 없기 때문이다. 이 값은 여전히 DB2에서 처리될 수 있지만, 이것을 XML 컬럼에 삽입하거나, 애플리케이션에서 XML 파서를 사용하여 파싱할 수 없다. 잘 구성된 XML 문서를 만들어야 한다면, 컬럼 문에 있는 경로 식을 '<phones>{phone}</phones>'으로 바꾸는 등, 새로운 루트 엘리먼트로 전화 엘리먼트의 시퀀스를 래핑한다.
여러 전화 컬럼들 리턴하기
여러 전화 번호들을 하나의 Varchar 또는 XML 값으로 결합하려면 애플리케이션에 추가 코드가 개별 번호들을 사용하도록 해야 한다. 개별 Varchar 값으로서 각 전화 번호를 리턴하고 싶다면, phone 컬럼의 고정된 번호를 만들어냄으로써 이를 수행한다. Listing 10은 위치 술어를 사용하여 두 컬럼에 전화 번호들을 리턴한다.
Listing 10. 여러 전화 번호 컬럼들을 리턴하기
SELECT X.* FROM emp ,
XMLTABLE ('$d/dept/employee' passing doc as "d"
COLUMNS
first VARCHAR(25) PATH 'name/first',
last VARCHAR(25) PATH 'name/last',
phone VARCHAR(12) PATH 'phone[1]',
phone2 VARCHAR(12) PATH 'phone[2]'
) AS X
|
Listing 10의 쿼리 결과는 다음과 같다.
first last phone phone2
---------------- --------------- ------------ ------------
John Doe - -
Peter Pan 905-416-5004 -
Mary Jones 905-403-6112 647-504-4546
3 record(s) selected.
|
이러한 방식의 단점은 아이템의 변동 가능한 번호가 고정된 아이템의 변이 가능한 번호가 컬럼의 고정된 번호로 매핑된다는 점이다. 사원들은 예상했던 것보다 더 많은 전화 번호를 가질 수 있다. 다른 사람들은 더 적은 전화 번호를 가질 수 있다. 하지만, 모든 사원이 정확히 한 개의 회사 전화 번호와 한 개의 휴대 전화를 갖고 있다면, 두 개의 컬럼과 상응하는 이름을 만들어 내는 것이 매우 유용하다.
전화 번호 당 한 개의 행 리턴하기
개별 컬럼에 전화 번호를 리턴하는 대신, XMLTABLE을 사용하여 개별 행들에 리턴할 수 있다. 이 경우, 사원 당 한 행 보다는 전화 번호 당 한 행을 리턴해야 한다. 이는 이름과 성에 대한 컬럼에 반복되는 정보를 가져올 수 있다. Listing 11은 XMLTABLE 함수에 행- 생성 XPath 식을 수정하여 전화 번호에 대한 관계형 행을 만들 경우 어떤 일이 발생하는지를 보여주고 있다.
Listing 11. 전화 번호 당 한 개의 행 만들기
SELECT X.* FROM emp ,
XMLTABLE ('$d/dept/employee/phone' passing doc as "d"
COLUMNS
first VARCHAR(5) PATH '../name/first',
last VARCHAR(5) PATH '../name/last',
phone VARCHAR(12) PATH '.'
) AS X
|
이전 쿼리들과 비교해 볼 때, Listing 11은 행-생성 식과 컬럼-생성 식에 다른 XPath를 사용한다. 콘텍스트가 employee 엘리먼트가 아닌 phone 엘리먼트이기 때문에 COLUMNS 구문의 XPath 식은 이에 따라 변한다. First name과 last name에 대한 경로는 부모 단계로 시작한다. name은 phone과 형제기 때문이다. 이 쿼리의 결과에는 employee Mary Jones에 대한 두 개의 관계형 행이 포함되어 있고, 각각 전화 번호가 있다.
first last phone
----- ----- ------------
Peter Pan 905-416-5004
Mary Jones 905-403-6112
Mary Jones 647-504-4546
3 record(s) selected.
|
비-존재 경로
왜 Listing 11이 employee John Doe의 행을 리턴하지 않았는지 궁금할 것이다. Listing 11의 행-생성 식이 문서에 있는 모든 phone 엘리먼트를 반복했고, employee John Doe에 대한 어떤 phone 엘리먼트도 없었다. 결국, John Doe에 대한 employee 엘리먼트는 전혀 처리되지 않는다. 이를 인식하지 못하면, 문제가 될 수 있고, 불완전한 사원 리스트가 만들어 진다.
이를 피하기 위해, 사원이 phone 엘리먼트를 갖고 있지 않더라도 각 사원에 대한 행이 생성되어야 한다. 가능한 솔루션은 phone 엘리먼트가 존재하지 않을 때마다 name 엘리먼트(phone의 형제)에 대한 행을 만드는 것이다. 다음의 콤마 분리 리스트 식을 사용하여 이를 수행한다: '(phone,
.[fn:not(phone)]/name)' 두 식의 결과는 하나의 시퀀스로 결합된다. 하지만, 이 경우, 두 개의 식들 중 하나는 언제나 빈 결과를 만들어 낸다. 하나의 사원이 한 개 이상의 phone 엘리먼트를 갖고 있지 않으면, name 엘리먼트가 리턴된다. fn:not 함수는 이름과 전화 번호를 가진 그러한 사원들에 대한 중복 행을 피한다. (Listing 12)
Listing 12. 전화 번호나 이름에 대한 행 만들기
SELECT X.* FROM emp ,
XMLTABLE ('$d/dept/employee/(phone,.[fn:not(phone)]/name)' passing doc as "d"
COLUMNS
first VARCHAR(5) PATH '../name/first',
last VARCHAR(5) PATH '../name/last',
phone VARCHAR(12) PATH '.[../phone]'
) AS X
|
Listing 12는 어떤 phone 엘리먼트가 존재하지 않을 때에도, phone 엘리먼트와 name 엘리먼트에 대한 행을 만들어 낸다. 사원이 전화 번호를 갖고 있지 않을 경우, 전화 번호 정보 없이, 그 사원에 대한 한 행만 리턴한다.
first last phone
----- ----- ------------
John Doe -
Peter Pan 905-416-5004
Mary Jones 905-403-6112
Mary Jones 647-504-4546
4 record(s) selected.
|
네임스페이스(Namespaces)가 있는 XMLTABLE
XML 네임스페이스는 XML 문서에 고유의 이름을 가진 엘리먼트와 애트리뷰트를 제공하는 W3C XML 표준이다. XML 문서에는 다른 어휘들로부터 온 엘리먼트와 애트리뷰트가 포함되지만, 같은 이름을 갖고 있다. 각 어휘에 네임스페이스를 부여함으로써, 동일한 엘리먼트나 애트리뷰트 이름 사이의 모호함이 해소된다. DB2 9의 모든 pureXML은 SQL/XML, XQuery, XML 인덱스, XML 스키마 핸들링 같은 XML 네임스페이스를 지원한다. (네임스페이스로 XML 데이터 쿼리하기 - 참고자료)
XML 문서에서, 보유한 애트리뷰트 xmlns로 XML 네임스페이스를 선언한다. 이것의 값에는 Universal Resource Identifier (URI)가 포함되어야 한다. URI는 식별자로서 사용된다. URL처럼 보이지만, 기존 웹 페이지를 가리켜서는 안된다. 네임스페이스 선언 역시 접두사를 포함하고 있는데, 이는 엘리먼트와 애트리뷰트를 구분하는데 사용된다. 아래는 접두사가 있는(없는) 네임스페이스 선언 예제이다.
xmlns:ibm = "http://www.ibm.com/xmltable/"
xmlns = "http://www.ibm.com/xmltable/"
|
XMLTABLE에 네임스페이스의 사용을 표시하기 위해, 샘플 문서가 표 1에 추가되었다. 표 1에 사용된 다른 문서와는 달리, 이 새로운 문서에는 접두사 ibm을 이용한 네임스페이스 선언이 포함되어 있다.
Listing 13. 접두사로 네임스페이스 선언을 포함하고 있는 문서 샘플
<ibm:dept bldg="123" xmlns:ibm="http://www.ibm.com/xmltable">
<ibm:employee id="144">
<ibm:name>
<ibm:first>James</ibm:first>
<ibm:last>Bond</ibm:last>
</ibm:name>
<ibm:office>007</ibm:office>
<ibm:phone>905-007-1007</ibm:phone>
<ibm:salary currency="USD">77007</ibm:salary>
</ibm:employee>
</ibm:dept>
|
Listing 1의 쿼리를 다시 실행하고 아웃풋을 검사한다.
DB2에서 이 쿼리를 실행하면 다음과 같은 아웃풋이 만들어진다.
empID firstname lastname
----------- -------------------- -------------------------
901 John Doe
902 Peter Pan
903 Mary Jones
|
여러분도 보듯, employee James Bond에 대한 정보가 리턴되지 않았다. Listing 1이 네임스페이스가 없는 엘리먼트 이름만 참조하기 때문이다. 데이터베이스에 있는 모든 사원들을 리턴하려면, Listing 14의 경로 식에 네임스페이스 접두사용 * wildcard를 사용할 수 있다. 이렇게 하면, wildcard (*)가 어떤 네임스페이스도 포함하고 있지 않은 네임스페이스와도 매치하기 때문에, 네임스페이스와 관계 없이 모든 엘리먼트들이 간주된다.
Listing 14. 모든 네임스페이스와 매치하는 wildcard (*) 사용하기
SELECT X.*
FROM emp,
XMLTABLE ('$d/*:dept/*:employee' passing doc as "d"
COLUMNS
empID INTEGER PATH '*:@id',
firstname VARCHAR(20) PATH '*:name/*:first',
lastname VARCHAR(25) PATH '*:name/*:last') AS X
|
문서에서 모든 네임스페이스와 매치하도록 와일드카드를 사용한 결과, 모든 사원들이 리턴된다.
empID firstname lastname
----------- -------------------- -------------------------
901 John Doe
902 Peter Pan
903 Mary Jones
144 James Bond
4 record(s) selected.
|
이런 특정 데이터의 경우, 애트리뷰트 @id에 대한 네임스페이스 와일드카드가 반드시 필요한 것은 아니었다. @id 애트리뷰트 employee James Bond는 어떤 네임스페이스도 없기 때문이다. 애트리뷰트는 엘리먼트에서 네임스페이스를 상속 받지 않으며, 기본 네임스페이스도 간주하지 않는다. 따라서, 애트리뷰트 이름에 접두사가 없다면, 어떤 네임스페이스에도 속하지 않은 것이다.
와일드카드의 사용은 네임스페이스에 관계 없이 모든 사원들을 리턴하는 가장 간단한 방법이다. 다음에는, ibm 네임스페이스에 있는 사원들에 대한 정보만 리턴하는 방법을 보자. XQuery나 XPath 식에 네임스페이스를 지정하는 두 가지 방법이 있다:
기본 네임스페이스 선언하기
쿼리하고자 하는 모든 엘리먼트들이 같은 네임스페이스에 속할 때, 기본 네임스페이스를 선언하는 것이 가장 간단한 방법이 될 수 있다. XQuery 식의 앞에 기본 네임스페이스를 선언해야 하고, 그 뒤에 여러분이 선호하는 모든 엘리먼트와 애트리뷰트 이름들이 그 네임스페이스에 묶인다. (Listing 15)
Listing 15. 기본 네임스페이스 선언 사용하기
SELECT X.*
FROM emp,
XMLTABLE ('declare default element namespace "http://www.ibm.com/xmltable";
$d/dept/employee' passing doc as "d"
COLUMNS
empID INTEGER PATH '@id',
firstname VARCHAR(20) PATH
'declare default element namespace "http://www.ibm.com/xmltable"; name/first',
lastname VARCHAR(25) PATH
'declare default element namespace "http://www.ibm.com/xmltable"; name/last') AS X
|
네임스페이스 선언을 사용하면 네임스페이스 ibm에서 사원들을 필터링 할 수 있다. Listing 15의 아웃풋은 다음과 같다.
EMPID FIRSTNAME LASTNAME
----------- -------------------- -------------------------
144 James Bond
1 record(s) selected.
|
컬럼-생성 식은 행-생성 식에서 네임스페이스 선언을 상속받지 않는다. 각 컬럼-생성 식은 개별적인 XQuery이고, 고유의 네임스페이스 선언을 필요로 한다. 이러한 네임스페이스 선언은, 문서가 여러 네임스페이스를 포함하고 있을 경우 서로 다르다. 단 하나의 네임스페이스가 있는 경우도 종종 있다. 이 경우, XMLTABLE 함수에 있는 모든 식에 하나의 네임스페이스를 선언하는 것이 편리하다. 이것은 XMLNAMESPACES() 함수를 사용함으로써 이루어 질 수 있다. 이 함수는 XMLTABLE과 기타 SQL/XML 함수 내에 기본적인 네임스페이스와 여러 네임스페이스 접두사를 선언할 수 있다. XMLNAMESPACES 함수를 사용할 때의 장점은 선언된 네임스페이스가 XMLTABLE 콘텍스트의 모든 식에 대해 글로벌이기 때문에, 모든 XQuery 식은 이러한 네임스페이스 선언을 알아야 하고 반복된 네임스페이스 선언들은 필요가 없다.
XMLNAMESPACES() 함수를 사용하여 Listing 15를 다시 작성해 보자.
Listing 16. XMLNAMESPACES()를 사용하여 기본 네임스페이스 선언하기
SELECT X.*
FROM emp,
XMLTABLE (XMLNAMESPACES(DEFAULT 'http://www.ibm.com/xmltable'),
'$d/dept/employee' passing doc as "d"
COLUMNS
empID INTEGER PATH '@id',
firstname VARCHAR(20) PATH 'name/first',
lastname VARCHAR(25) PATH 'name/last') AS X
|
XMLNAMESPACES() 함수에 의해 선언된 기본 네임스페이스는 행-생성 식과 모든 컬럼-생성 식에 적용된다. 단 하나의 네임스페이스 선언이 XMLTABLE() 함수의 모든 XQuery 식에 필요하다. Listing 16의 결과는 Listing 15와 똑같다.
네임스페이스 접두사 선언하기
단 하나의 네임스페이스가 문서에 있을 때 기본 네임스페이스가 일반적인 솔루션이지만, 문서에 여러 네임스페이스가 포함되어 있을 경우에는 다른 방식이 필요하다. 기본 네임스페이스만 사용하면 그 네임스페이스에서 엘리먼트와 애트리뷰트를 선택할 수 있고, 와일드카드를 사용하면 모든 네임스페이스에서 엘리먼트와 애트리뷰트를 선택한다. 여러 특정 네임스페이스에서 엘리먼트와 애트리뷰트를 선택하려면, 네임스페이스 접두사를 사용하는 것이 최상의 옵션이다.
XMLNAMESPACES 함수를 사용하지 않는다면, 이 네임스페이스 접두사는 모든 식에 선언되어야 한다. 하지만, 기본 네임스페이스와 마찬가지로, XMLNAMESPACES 함수를 사용하여 반복되는 네임스페이스 선언을 피할 수 있다. Listing 17은 XMLTABLE 함수에 네임스페이스 접두사를 선언하는 방법이다.
Listing 17. XMLNAMESPACES() 함수를 사용하여 네임스페이스 접두사 선언하기
SELECT X.*
FROM emp,
XMLTABLE (XMLNAMESPACES('http://www.ibm.com/xmltable' as "ibm"),
'$d/ibm:dept/ibm:employee' passing doc as "d"
COLUMNS
empID INTEGER PATH '@id',
firstname VARCHAR(20) PATH 'ibm:name/ibm:first',
lastname VARCHAR(25) PATH 'ibm:name/ibm:last') AS X
|
예상했던 대로, Listing 17은 Listing 16과 같은 결과를 리턴한다.
EMPID FIRSTNAME LASTNAME
----------- -------------------- -------------------------
144 James Bond
1 record(s) selected.
|
요약
XMLTABLE 시리즈 Part 1에서는 XMLTABLE을 사용하여 관계형 포맷으로 XML 데이터를 가져오는 방법, 반복 또는 소실 XML 엘리먼트와 비 존재 경로를 다루는 방법, XMLTABLE 함수에서 네임스페이스 핸들하는 방법을 배웠다. DB2 LUW와 DB2/zOS에서 XML 데이터를 쿼리하는 매우 강력한 기능들이다. 본 시리즈 Part 2에서는, XML을 관계형 테이블로 나누기, 큰 문서를 작은 문서들로 나누기, XML 데이터를 통한 관계형 뷰 같은 XMLTABLE 사용 시나리오에 대해 배우도록 하겠다.
감사의 말
이 글에 도움을 준 Cindy Saracco에게 감사의 말을 전한다.
참고자료 교육
제품 및 기술 얻기
토론
필자소개  | 
|  | Nicola 박사는 IBM Silicon Valley Lab의 XML 데이터베이스 성능 분야 기술 리더이다. XQuery, SQL/XML을 포함하여 DB2에서의 XML 성능을 연구하고 있다. DB2 XML 개발 팀은 물론, XML을 사용하는 고객과 비즈니스 파트너들과 긴밀히 협력하고 있다. IBM에 입사하기 전에, Informix Software에서 데이터 웨어하우징 성능 분야에서 일했다. 분산 및 복제 데이터베이스 관련 프로젝트도 수행했다. 1999년, 독일 Technical University of Aachen에서 컴퓨터 공학 박사 학위를 받았다. |
 | 
|  | Vitor Rodrigues는 IBM Silicon Valley Lab의 소프트웨어 개발자이다. 포르투갈의 University of Minho에서 컴퓨터 공학과 시스템 엔지니어링을 전공했다. 2005년에 IBM의 DB2 Everyplace와 DB2 9 pureXML 분야에서 인턴으로 근무했다. pureXML용 DB2 9 QA 팀의 멤버이며, 이곳에서 DB9의 XML 기능을 연구하고 있다. 인턴쉽이 끝난 후, 정식 직원이 되었으며, 현재, DB2 9 XML Enablement 팀에서 일하고 있다. |
기사에 대한 평가
|  |