XML 쿼리 언어

XML Query Language

XML 쿼리 언어

SMaker님의 글을 전문인용하여 재구성하였다. - http://xe.xpressengine.net/wiki/18180631

  • 개요
  • 쿼리 사용방법
  • XML sample
  • Select query 예제
  • Join Select 예제
  • Letf Join Select 예제
  • Insert 예제
  • update 예제
  • delete 예제
  • Select Click Count 예제

개요

  • XpressEngine는 SQL 쿼리를 그대로 사용하지 않고 XML로 작성합니다.
  • 이는 다양한 DBMS를 지원하기 위해서입니다.
  • XML Query문의 확장자는 .xml 입니다.

쿼리 사용방법

XML 쿼리는 모듈과 애드온, 위젯 등에서 다음과 같이 사용할 수 있습니다.

$args->name = 'zero';
$output = executeQuery('member.getMemberInfo', $args);

XML Query를 호출하여 실제 DB의 데이터를 받거나 조작하기 위해서 사용되는 executeQuery() 함수는 DB::executeQuery() 함수의 별칭(alias)입니다.

이 함수는 실제 DB 데이터를 조작하고 사용된 DB에 따라 XML 쿼리가 네이티브 SQL로 파싱된 후에 결과를 수신합니다.

function executeQuery($xml_query_name, $args = null);

첫번째 파라미터는 실행하고자 하는 XML 쿼리의 이름입니다. 이름은 모듈이나 위젯, 애드온에 따라 다음과 같이 사용합니다.

  • 모듈에서 XML Query를 실행하고자 하는 경우 - 모듈이름.쿼리ID
    ex) $output = executeQuery('communication.getMessage',$args, $columnList);
  • 위젯에서 XML Query를 실행하고자 하는 경우 - widgets.위젯이름.쿼리ID
    ex) $output = executeQueryArray('widgets.content.getMids', $obj);
  • 애드온에서 XML Query를 실행하고자 하는 경우 - addons.애드온이름.쿼리ID
    ex) $output = executeQueryArray('addons.piclens.getFileList', $obj);

두번째 파라미터 $args는 널(null)이 될 수도 있고 해당 XML Query에서 필요시 stdClass의 variables type으로 변수의 key, value를 설정 후 데이터를 쿼리에 전달하는데 사용됩니다.

결과는 Object class의 객체로 반환(return) 됩니다.

  • 쿼리가 실패했다면 $output->toBool()이 FALSE 일 경우이고, TRUE이면 쿼리는 정상적으로 실행이 된 것을 의미합니다.
  • select문의 결과 데이터는 $ouptut->data 변수에 담겨져 return 됩니다.

XML 쿼리 예제(sample)

쿼리ID.xml

<query id="쿼리아이디" action="select|update|delete|insert">
    <tables>
        <table name="원테이블이름" alias="alias" />
        ...
    </tables>

    <columns>
        <column name="컬럼명" alias="alias" />
        ...
    </columns>

    <conditions>
        <condition operation="조건절" column="Column명" var="변수명" filter="필터형식" default="기본값" notnull="notnull" minlength="최소길이" maxlength="최대길이" pipe="연결연산자" />
        ...
        <group pipe="연결연산자">
            <condition operation="조건절" column="Column명" var="변수명" filter="필터형식" default="기본값" notnull="notnull" minlength="최소길이" maxlength="최대길이" pipe="연결연산자" />
            ...
        </group>
        ...
    </conditions>

    <navigation>
        <index var="이름" default="기본값" order="desc|asc" />
        <list_count var="변수명" default="기본값" />
        <page_count var="변수명" default="기본값" />
        <page var="변수명" default="변수명" />
    </navigation>

    <groups>
        <group column="GroupBy 대상" />
    </groups>
</query>

XML 쿼리 요소와 속성

XML 쿼리에 사용되는 XML 요소와 속성은 다음과 같습니다.

<query> - 쿼리 XML의 최상위 요소

  • id : 쿼리를 찾을 수 있는 아이디입니다. module.query_id를 사용해서 쿼리 XML 파일을 검색하고 사용합니다.
  • action : 액션은 select, update, delete, insert 4가지 타입입니다.

<tables> - 쿼리에 사용될 테이블의 모음

  • <table> : 테이블 요소, 테이블 조인 시 여러 개의 <table>을 사용할 수 있습니다.
  • name : 원 테이블 명 (XE에서의 테이블 머릿말(접두어) prefix_는 무시)
  • alias : 열 지정이나 검색 등에서 사용할 테이블 별칭, join 또는 다른 용도로 원 테이블 명을 바꾸어 사용할 경우

<columns> - 쿼리에 사용될 열 모음

  • <column> : 열 요소, 처리하고자 하는 컬럼명을 입력하시면 됩니다.
  • name : 열 이름(컬럼명)
  • alias : 원래 열의 이름을 변경할 때 사용(다른 이름으로 바꾸어 결과를 만들고자 할 경우 지정)

<conditions> - 조건문을 만들 때 사용

  • 조건절을 구성합니다.
  • 조건절을 여러 개의 그룹으로 사용하고자 할 때에는 <group> 태그를 이용해 묶어 주실 수 있습니다.

<group> ... </group> - 조건 그룹

  • 조건문을 그룹으로 사용할 경우 pipe="and|or" 을 이용하여 그룹끼리의 조건을 지정할 수 있습니다.

<column> - 조건문

operation

아래와 같은 연산자로 처리할 수 있습니다.

  • equal : column = (var|default)
  • more : column >= (var|default)
  • excess : column > (var|default)
  • less : column <= (var|default)
  • below : column < (var|default)
  • notequal : column != (var|default)
  • notnull : column is not null
  • null : column is null
  • like_prefix : column like '%var|default'
  • like_tail : column like 'var|default%'
  • like : column like '%var|default%'
  • in : column in (var|default)
  • notin : column not in (var|default)
column 컬럼명(열 이름)을 지정합니다.
var executeQuery(Array)() 함수에서 2번째 파라미터인 stdClass의 키(key)값을 지정합니다.
filter

var 값의 조건 필터링. filter에 맞지 않으면 var 값이 null이 되어 default 값으로 대체됩니다. 아래와 같은 filter를 지원합니다.

  • email, email_address : 메일 형식
  • homepage : http|https:// 같은 웹사이트 주소 형식
  • userid, user_id : XE의 사용자 아이디 형식 (첫 두 글자는 영문, 세번째 문자부터는 숫자+영문+_ 형식입니다.)
  • number : 숫자만 허용
  • alpha : 영문 알파벳만 허용
  • alpha_number : 숫자와 문자 모두 허용
default

var 값이 null 일 경우 default 값으로 대체됩니다. 기본값은 일반 문자열, 숫자 모두 사용 가능하며, 아래와 같은 함수를 사용할 수도 있습니다.

  • ipaddress() : 접속자의 ip 주소
  • unixtime() : 유닉스 시간(php의 time() 함수)
  • curdate() : 현재 시간 (YYYYMMDDHHIISS)
  • plus(int count) : column = column + count
  • minus(int count) : column = column - count
  • multiply(int arg) : column = column * arg
  • sequence() : XE의 getNextSequence()를 실행
notnull null 인지 확인, 지정하면 반드시 var의 값이 있어야 합니다. (not null check)
minlength 최소 길이를 검사합니다.
maxlength 최대 길이를 검사합니다.
pipe and|or 등의 조건을 지정할 수 있습니다.

<navigation> - navigation은 정렬 순서(order by) 또는 페이징 기능을 지원합니다.

<index> 정렬할 칼럼과 정렬 방법을 지정할 수 있습니다.
  • var : 대상 컬럼명을 담은 변수명(열 이름이 값인 변수 이름)
  • default : var 값이 지정되지 않은 경우 기본으로 정렬할 컬럼명 지정
  • order : asc(오름차순)|desc(내림차순)
<ist_count> 페이징 결과를 받을 수 있습니다.
  • var : 목록의 rows를 지정, 행의 개수가 값인 변수 이름
  • default : var 값이 지정되지 않으면 기본 rows 값
<page_count> 페이징 계산 시에 페이지 네비게이션의 수를 지정
  • var : 페이지 네비게이션의 수
  • default : var 값이 없을 경우 기본 페이징 네비게이션의 수
<page> 현재 페이지 번호 지정, 현재 몇 번째 페이지인지를 지정할 수 있습니다.
  • var : 현재 몇번째 페이지인지를 지정할 변수
  • default : var 값이 지정되지 않았을 경우 페이지 번호

<groups> - 조건문에 따라 그룹을 사용할 수 있게 합니다.(group by 절 사용시 작성)

  • <group> 그룹핑할 컬럼을 지정할 수 있습니다.
  • column : 그룹핑할 컬럼명 지정(group by 기준 열 이름)

Select query 예제

member.getMemberList : member테이블에서 특정 조건을 가진 회원들을 페이징을 하면서 select

    <query id="getMemberList" action="select">
    <tables>
       <table name="member" />
    </tables>

    <columns>
       <column name="*" />
    </columns>

    <conditions>
        <condition operation="equal" column="is_admin" var="is_admin" />
       <condition operation="equal" column="denied" var="is_denied" pipe="and" />
       <group pipe="and">
            <condition operation="like" column="user_id" var="s_user_id" />
            <condition operation="like" column="user_name" var="s_user_name" pipe="or" />
            <condition operation="like" column="nick_name" var="s_nick_name" pipe="or" />
            <condition operation="like" column="email_address" var="s_email_address" pipe="or" />
            <condition operation="like_prefix" column="regdate" var="s_regdate" pipe="or" />
            <condition operation="like_prefix" column="last_login" var="s_last_login" pipe="or" />
        </group>
    </conditions>

    <navigation>
        <index var="sort_index" default="member_srl" order="desc" />
        <list_count var="list_count" default="20" />
        <page_count var="page_count" default="10" />
        <page var="page" default="1" />
    </navigation>
    </query>

document.getMonthlyArchivedList : 모듈을 '년월'일을 기준으로 group by 한 결과를 가져옴

<query id="getMonthlyArchivedList" action="select">
<tables>
    <table name="documents" />
</tables>

<columns>
    <column name="substr(regdate,1,6)" alias="month"/>
    <column name="count(*)" alias="count" />
</columns>

<conditions>
   <condition operation="in" column="module_srl" var="module_srl" filter="number" />
</conditions>

<groups>
    <group column="substr(regdate,1,6)" />
</groups>
</query>

Join Select 예제

document.getTrashList 예제입니다.

<query id="getTrashList" action="select">
    <tables>
        <table name="documents" />
        <table name="document_trash" />
    </tables>
    <columns>
        <column name="documents.*" />
        <column name="document_trash.trash_srl" alias="trash_srl" />
        <column name="document_trash.module_srl" alias="module_srl" />
        <column name="document_trash.trash_date" alias="trash_date" />
        <column name="document_trash.description" alias="trash_description" />
        <column name="document_trash.ipaddress" alias="trash_ipaddress" />
        <column name="document_trash.user_id" alias="trash_user_id" />
        <column name="document_trash.user_name" alias="trash_user_name" />
        <column name="document_trash.nick_name" alias="trash_nick_name" />
        <column name="document_trash.member_srl" alias="trash_member_srl" />
    </columns>
    <conditions>
        <condition operation="equal" column="document_trash.document_srl" default="documents.document_srl" notnull="notnull" />
        <condition operation="in" column="document_trash.module_srl" var="module_srl" filter="number" pipe="and" />
        <condition operation="equal" column="document_trash.member_srl" var="member_srl" filter="number" pipe="and" />

        <group pipe="and">
            <condition operation="like" column="documents.title" var="s_title" />
            <condition operation="like" column="documents.content" var="s_content" pipe="or" />
            <condition operation="like" column="documents.user_name" var="s_user_name" pipe="or" />
            <condition operation="like" column="documents.user_id" var="s_user_id" pipe="or" />
            <condition operation="like" column="documents.nick_name" var="s_nick_name" pipe="or" />
            <condition operation="like" column="documents.email_address" var="s_email_addres" pipe="or" />
            <condition operation="like" column="documents.homepage" var="s_homepage" pipe="or" />
            <condition operation="like" column="documents.tags" var="s_tags" pipe="or" />
            <condition operation="equal" column="documents.is_secret" var="s_is_secret" pipe="or" />
            <condition operation="equal" column="documents.member_srl" var="s_member_srl" pipe="or" />
            <condition operation="more" column="documents.readed_count" var="s_readed_count" pipe="or" />
            <condition operation="more" column="documents.voted_count" var="s_voted_count" pipe="or" />
            <condition operation="more" column="documents.comment_count" var="s_comment_count" pipe="or" />
            <condition operation="more" column="documents.trackback_count" var="s_trackback_count" pipe="or" />
            <condition operation="more" column="documents.uploaded_count" var="s_uploaded_count" pipe="or" />
            <condition operation="like_prefix" column="documents.regdate" var="s_regdate" pipe="or" />
            <condition operation="like_prefix" column="documents.last_update" var="s_last_update" pipe="or" />
            <condition operation="like_prefix" column="documents.ipaddress" var="s_ipaddress" pipe="or" />
        </group>

    </conditions>
    <navigation>
        <index var="sort_index" default="documents.list_order" order="order_type" />
        <list_count var="list_count" default="20" />
        <page_count var="page_count" default="10" />
        <page var="page" default="1" />
    </navigation>
</query>

Letf Join Select 예제

<query id="getDocumentsExtraVars" action="select">
    <tables>
        <table name="document_extra_keys" alias="extra_keys" />
        <table name="document_extra_vars" alias="extra_vars" type="left join">
            <conditions>
                <condition operation="equal" column="extra_keys.module_srl" default="extra_vars.module_srl" />
                <condition operation="in" column="extra_vars.document_srl" var="document_srl" pipe="and" />
                <condition operation="equal" column="extra_keys.eid" default="extra_vars.eid" pipe="and" />
            </conditions>
        </table>
    </tables>
    <columns>
        <column name="extra_keys.module_srl" alias="module_srl" />
        <column name="extra_keys.var_name" alias="name" />
        <column name="extra_keys.var_type" alias="type" />
        <column name="extra_keys.var_is_required" alias="is_required" />
        <column name="extra_keys.var_search" alias="search" />
        <column name="extra_keys.var_default" alias="default" />
        <column name="extra_keys.var_desc" alias="desc" />
        <column name="extra_keys.var_idx" alias="idx" />
        <column name="extra_vars.document_srl" alias="document_srl" />
        <column name="extra_vars.lang_code" alias="lang_code" />
        <column name="extra_vars.value" alias="value" />
        <column name="extra_keys.eid" alias="eid" />
    </columns>
    <navigation>
        <index var="sort_index" default="extra_keys.var_idx" order="asc" />
    </navigation>
</query>

Insert 예제

document.insertCategory : 문서 카테고리 추가

<query id="insertCategory" action="insert">
<tables>
    <table name="document_categories" />
</tables>

<columns>
    <column name="category_srl" var="category_srl" filter="number" notnull="notnull" />
    <column name="module_srl" var="module_srl" filter="number" default="0" notnull="notnull" />
    <column name="title" var="title" notnull="notnull" minlength="2" maxlength="250" />
    <column name="document_count" var="document_count" default="0" />
    <column name="regdate" var="regdate" default="curdate()" />
    <column name="last_update" var="last_update" default="curdate()" />
    <column name="list_order" var="list_order" default="0" />
</columns>
</query>

update 예제

document.updateCategory : 특정 카테고리의 제목이나 순서, 최근 수정일을 변경

<query id="updateCategory" action="update">
<tables>
    <table name="document_categories" />
</tables>

<columns>
    <column name="title" var="title" />
    <column name="list_order" var="list_order" />
    <column name="last_update" var="last_update" default="curdate()" />
</columns>

<conditions>
    <condition operation="equal" column="category_srl" var="category_srl" filter="number" notnull="notnull" />
</conditions>
</query>

delete 예제

document.deleteCategory : 특정 카테고리를 삭제

<query id="deleteCategory" action="delete">
<tables>
    <table name="document_categories" />
</tables>

<conditions>
    <condition operation="equal" column="category_srl" var="category_srl" filter="number" notnull="notnull" />
</conditions>
</query>

Select Click Count 예제

Select 시 조회수 등의 정수의 숫자 컬럼을 +1 하는 기능입니다.
Cubrid의 경우에는 incr()이라는 함수를 사용하고 다른 데이타베이스의 경우 해당 컬럼을 Select후 Update 합니다.

document.getDocument XML Query에 Click Count 를 적용해 본 예제입니다. select시 정수 숫자 컬럼 node에 attribute는 click_count, 값은 Argument로 매핑되는 변수명을 기입합니다.

<query id="getDocument" action="select">
    <tables>
        <table name="documents" />
    </tables>

    <columns>
        <column name="document_srl" />
        <column name="module_srl" />
        <column name="category_srl" />
        <column name="lang_code" />
        <column name="is_notice"  />
        <column name="is_secret"  />
        <column name="title"  />
        <column name="title_bold" />
        <column name="title_color" />
        <column name="content"  />
        <column name="readed_count" click_count="incr_readed_count"/>
        <column name="voted_count" />
        <column name="blamed_count" />
        <column name="comment_count" />
        <column name="trackback_count" />
        <column name="uploaded_count" />
        <column name="password"  />
        <column name="user_id"  />
        <column name="user_name"  />
        <column name="nick_name" />
        <column name="member_srl"  />
        <column name="email_address"  />
        <column name="homepage" />
        <column name="tags" />
        <column name="extra_vars" />
        <column name="regdate" />
        <column name="last_update"  />
        <column name="last_updater" />
        <column name="ipaddress"  />
        <column name="list_order"  />
        <column name="update_order"  />
        <column name="allow_comment"  />
        <column name="lock_comment" />
        <column name="allow_trackback" />
        <column name="notify_message" />
    </columns>
    <conditions>
        <condition operation="equal" column="document_srl" var="document_srl" filter="number" notnull="notnull" />
    </conditions>
</query>

click_count 의 매핑변수 값이 true이면 해당 컬럼을 +1 증가합니다.

$args->document_srl = $this->document_srl;
$args->incr_readed_count = true;
$output = executeQuery('document.getDocument', $args);