1. EQLについて
EQL(Entity Query Language)はiPLAss内に保存されているEntityを検索するためのクエリ言語です。 SQLのSELECT文と似た構文となっています。 SQLにおけるテーブルをEntity、カラムをプロパティと置き換えて考えることができます。
以下にEQLの例を示します。
SELECT oid, name, mail FROM mtp.auth.User WHERE accountId='scott' ORDER BY name
参照プロパティとして定義されている関連するEntityを結合して、値を取得することも可能です。
SELECT oid, name, groups.name (1)
FROM mtp.auth.User WHERE groups.code='G01'
1 | [参照プロパティ名].[参照先Entityのプロパティ名]のように、.(ドット)区切りで指定することにより参照先のEntityの値を取得・指定可能です。 |
SQLと同様に集約関数の利用も可能です。
SELECT job, AVG(sal) FROM Employee GROUP BY job
1.1. 標準的なSQLとの差異
EQLの文法は標準的なSQLのSELECT文とほぼ同等ですが、次のような差異が存在します。
-
Entity間の結合について
参照(Reference)関係が定義されていないEntity同士を結合することはできません。 参照関係が定義されているEntityにおいて、JOIN句を記述する必要はありません。
SQLでの結合例SELECT job, ename, Department.dname FROM Employee LEFT OUTER JOIN Department ON Employee.deptno=Department.deptno
EQLでの結合例SELECT job, ename, department.dname FROM Employee (1)
1 事前にdepartmentという参照プロパティ名で参照先エンティティが定義されている必要があります SQLにおいては、結合の方法を指定可能(外部結合、内部結合、クロス結合)ですが、EQLにおける結合(参照)は常にFrom句に指定されたEntityを核としたLEFT OUTER JOINとなります。
また、SQLではJOIN句にて結合のためのキー項目以外の結合条件の指定も可能ですが、EQLにおいてはキー項目(Entityの場合、oidがキー項目となります)以外の結合条件を追加したい場合は、REFER句を利用します。
SQLでの結合例(キー項目以外に結合条件を指定する場合)SELECT job, ename, Department.dname FROM Employee LEFT OUTER JOIN Department ON Employee.deptno=Department.deptno AND Department.dname = 'SALES'
EQLでの結合例(キー項目以外に結合条件を指定する場合)SELECT job, ename, department.dname FROM Employee REFER department ON department.dname = 'SALES'
-
FROM句におけるサブクエリは未サポート
EQLにおいては、FROM句にサブクエリは指定できません。
-
集合演算子は未サポート
EQLにおいては、集合演算子(UNIONなど)は未サポートです。
-
別名は未サポート
EQLにおいては、Entity名、プロパティ名に別名を付与することはできません。
-
Entity名、プロパティ名はcase-sensitive
EQLにおいては、Entity名、プロパティ名はcase-sensitive(大文字・小文字を区別する)です。 ただし、EQL表現自体(SELECT、FROMなど)はcase-insensitive(大文字・小文字を区別しない)です。
-
*(アスタリスク)表現の未サポート
EQLにおいては、SELECT句にワイルドカードを表現する*(アスタリスク)は指定できません。 また、集約関数のCOUNTを利用する場合も*の指定はできません。 行数をカウントする場合は、
SELECT COUNT(*) FROM Employee
ではなく、
SELECT COUNT() FROM Employee
と*を指定しない表現形式となります。
-
相関サブクエリにおいて結合条件はON句で記述
EQLにおいては、相関サブクエリにおいて外側クエリとの結合条件はON句に記述します。
1.2. EQLの発行方法
EQLを実行する方法として、2つの方式が存在します。 EQLを文字列として作成し実行する方式、もしくはEQLを表現するクラス群を用いて実行する方式です。
EQL文字列からクエリを発行する
文字列でEQL文を作成した後、Queryインスタンスを生成しEntityManager経由でクエリを発行します。 次にサンプルコードを示します。
import org.iplass.mtp.ManagerLocator;
import org.iplass.mtp.entity.*;
import org.iplass.mtp.entity.query.*;
:
:
//EQL文字列からQueryインスタンスを生成
Query q = new Query("SELECT oid, name, mail FROM mtp.auth.User WHERE accountId='scott' ORDER BY name");
//EntityManagerを利用してクエリを発行
EntityManager em = ManagerLocator.manager(EntityManager.class);
SearchResult<Entity> result = em.searchEntity(q);
また、PreparedQueryを利用することにより、あらかじめ準備されたEQLのテンプレートにパラメータ変数を渡すことでQueryインスタンスを生成することも可能です。 次にサンプルコードを示します。
import org.iplass.mtp.ManagerLocator;
import org.iplass.mtp.entity.*;
import org.iplass.mtp.entity.query.*;
:
:
//あらかじめEQLのテンプレートを作成
PreparedQuery queryTemplate = new PreparedQuery("SELECT oid, name, mail FROM mtp.auth.User WHERE accountId='${aid}' and name='$s{inputVal}' ORDER BY name");(1)
:
:
//PreparedQueryから、パラメータaidに値を設定し、Queryインスタンスを生成
Map<String, Object> bindings = new HashMap<>();
bindings.put("aid", "scott");
bindings.put("inputVal", userInputValue);
Query q = queryTemplate.query(bindings);
//EntityManagerを利用してクエリを発行
EntityManager em = ManagerLocator.manager(EntityManager.class);
SearchResult<Entity> result = em.searchEntity(q);
1 | ${パラメータ名}の形でパラメータ定義可能です。Query生成時にそのパラメータ名で値を設定可能です。 また、GroovyTemplateの$s{ … }や$sl{ … }を利用することでエスケープ処理をすることができます。 |
EQLを表現するクラス群からクエリを発行する
EQLを表現するクラス群を利用してQueryを構築し、EntityManager経由でクエリを発行します。 EQLを表現するクラス群はorg.iplass.mtp.entity.queryパッケージ以下のクラスです。
次にサンプルコードを示します。
import org.iplass.mtp.ManagerLocator;
import org.iplass.mtp.entity.*;
import org.iplass.mtp.entity.query.*;
:
:
Query q = new Query()
.select("oid", "name", "mail")
.from("mtp.auth.User")
.where(new Equals("accountId", "scott"))
.order(new SortSpec("name", SortType.ASC));
EntityManager em = ManagerLocator.manager(EntityManager.class);
SearchResult<Entity> result = em.searchEntity(q);
2. 構成要素
EQLを構成する要素を以下に説明します。 あわせて、EQLの構文をBNF(Backus-Naur form)にて示します。
BNFを拡張した表現要素の説明
標準的なBNF表現に次の表現要素を拡張しています。 [ ] = オプションの要素 |
2.1. Query
EQL文全体を表す要素です。 Entityに対する問い合わせを表現します。 Queryを構成するためのクラス群はorg.iplass.mtp.entity.queryパッケージ以下に存在します。
SELECT job, ename, department.dname FROM Employee WHERE ename='john'
SELECT job, AVG(sal) FROM Employee GROUP BY job
SELECT job, ename, department.dname FROM Employee
REFER department ON department.dname = 'SALES'
SELECT /*+ no_index(job) native('ORDERED USE_NL_WITH_INDEX(...)') */
job, ename, department.dname FROM Employee
WHERE job = 'SALESMAN' AND sal > 1000 ORDER BY ename
LIMIT 100
Query q = new Query()
.select("job", "ename", "department.dname")
.from("Employee")
.where(new Equals("ename", "john"));
Query q = new Query()
.select("job", new Avg("sal"))
.from("Employee")
.groupBy("job");
Query q = new Query()
.select(
new EntityField("job"),
new EntityField("ename"),
new EntityField("department.dname"))
.from("Employee")
.refer("department", new Equals("department.dname", "SALES"));
Query q = new Query()
.select("job", "ename", "department.dname")
.hint(new NoIndexHint("job"))
.hint(new NativeHint("ORDERED USE_NL_WITH_INDEX(...)"))
.from("Employee")
.where(new And().eq("job", "SALESMAN").gt("sal", 1000L))
.order(new SortSpec("ename", SortType.ASC))
.limit(100);
構文
- <query> ::=
-
<select clause> <from clause> [<refer clause> {,<refer clause>}*] [<where clause>] [<group by clause>] [<having clause>] [<order by clause>] [<limit clause>]
- <select clause> ::=
-
SELECT <hint comment> [DISTINCT] "<value expression>" {,"<value expression>"}*
- "<hint comment>" ::=
-
"/*+" <hint expression>+ "*/"
- <hint expression> ::=
-
""ヒント表現""
- <from clause> ::=
-
FROM ""Entity定義名""
- "<refer clause>" ::=
-
REFER <reference> [ON "<condition>"] [AS OF NOW | "UPDATE TIME" | "<value expression>"]
- <where clause> ::=
-
WHERE "<condition>"
- <group by clause> ::=
-
GROUP BY "<value expression>" {,"<value expression>"}* [ROLLUP | CUBE]
- <having clause> ::=
-
HAVING "<condition>"
- <order by clause> ::=
-
ORDER BY <sort spec> {,<sort spec>}*
- <sort spec> ::=
-
"<value expression>" [ASC | DESC] [NULLS FIRST | NULLS LAST]
- "<limit clause>" ::=
-
LIMIT ""件数"" [OFFSET ""開始位置""]
- "<subquery>" ::=
-
(<query> [ON "<condition>"])
ヒントコメントについて
<hint comment>にて、Entity検索時のインデックス利用有無、DBネイティブのヒント句など、検索処理のチューニングを行うことが可能です。 <hint comment>は、/*+ */で囲まれ、SELECTの直後に配置します。 複数のヒント表現をスペース区切りで設定可能です。
EQLでは次のヒント表現をサポートします。
ヒント | 説明 |
---|---|
bind |
EQLに対して、実際にDBにクエリ発行する際にバインド変数(JDBCの場合PrepareStatement)を利用してリテラル値をセットすることを指定するヒントです。
上記の場合、'SALESMAN'、1000、100をバインド変数として実行します。 バインド対象のリテラル値にno_bindヒントを付与することで、当該のリテラル値をバインド対象外とすることも可能です。
上記の場合、1000、100をバインド変数として実行します。 |
cache |
EQLの実行結果のキャッシュを行うヒントです。 引数にてキャッシュのスコープ、キャッシュの有効期間(秒)を指定可能です。 キャッシュのスコープは以下のいずれかを設定可能です。
スコープ:TRANSACTIONの場合の記述例
スコープ:GLOBAL、キャッシュ期間:無期限の記述例
スコープ:GLOBAL、キャッシュ期間:10分の記述例
スコープ:GLOBAL_KEEP、キャッシュ期間:無期限の記述例
スコープ:GLOBAL_KEEP、キャッシュ期間:10分の記述例
スコープ:GLOBAL_RELOAD、リロード間隔:10分の記述例
|
fetch_size |
DBにクエリ発行する際のフェッチサイズ(JDBCの場合Statement#setFetchSize(int))を指定するヒントです。
|
index |
引数に指定されたプロパティを明示的に駆動するINDEXとして指定します。 INDEXとして指定するプロパティはEntity定義にて、INDEX、UNIQUE INDEX指定されている必要があります。
,(カンマ)区切りで複数のプロパティを指定可能(ただし、実際にどのINDEXから駆動するかの判断はDBに依存)です。
indexヒントもしくは、no_indexヒントが未指定の場合、どのプロパティのINDEXから駆動するかはDBに依存します。 |
native |
EQLが変換されたDBネイティブのSQL文(DBがRDBの場合)に付与するヒントを指定可能です。 引数にてネイティブのヒントを文字列として指定します。
テーブルに対するヒント句(MySQLのindex hintなど)を指定する場合は、第一引数にテーブル名を指定します。
|
no_bind |
EQLに対して、実際にDBにクエリ発行する際にバインド変数(JDBCの場合PrepareStatement)を利用しないことを指定するヒントです。
RdbAdapterService の設定により、EQL発行する際、常時バインドするように設定している場合、特定のEQLをバインドせずに実行するために指定します。 |
no_index |
引数に指定されたプロパティを駆動するINDEX選択対象から除外します。
,(カンマ)区切りで複数のプロパティを指定可能です。
indexヒントもしくは、no_indexヒントが未指定の場合、どのプロパティのINDEXから駆動するかはDBに依存します。 |
read_only |
EQLをリードオンリートランザクションとして発行したい場合、このヒント句を利用可能です。但し、検索時のSearchOptionのresultMode指定が
|
suppress_warnings |
EQLの警告ログの出力が必要ないことをマークするためのヒント句です。 EQL発行時に、検索条件にINDEXが付与されたプロパティが利用されていない場合など、警告ログが出力されます。 当該のEntityのデータ件数が少ないなどの理由で、警告ログの出力を抑制したい場合、このヒント句が利用可能です。
|
timeout |
クエリのタイムアウト秒(JDBCの場合Statement#setQueryTimeout(int))を設定可能です。 正確にタイムアウト秒で切断されるかはDBに依存します。
|
また、ヒント句を外部のプロパティファイルに定義し、そのプロパティファイルからキー名を指定して読み込むことが可能です。 プロパティファイルのパスは QueryService に定義します。
特にnativeヒント句を利用する場合、環境ごとに最適なヒント句が異なる場合があります。このような状況で、環境ごとに異なるヒント句を管理できるようになります。
hint1 = native(q0t0, 'FORCE INDEX(obj_store__USER_ISTR_index_3)')
hint2 = native(q0, 'FORCE INDEX(obj_store_ISTR_index_1)')
:
外部ヒント句は@hint("キー名")にて指定します。
上記プロパティファイルが定義されている環境において、
select /*+ @hint(hint1) */ a, b, c.x, d.x, d.name from SampleEntity where c.x='hoge' and a=1 and b=15
上記のEQLを発行した場合、これが、
select /*+ native(q0t0, 'FORCE INDEX(obj_store__USER_ISTR_index_3)') */ a, b, c.x, d.x, d.name from SampleEntity where c.x='hoge' and a=1 and b=15
と展開されます。
Queryクラスを利用する場合、Hint.externalHint(String)メソッドにて外部ファイルに定義されるHintをインスタンスとして取得可能です。
Query q = new Query()
.select("a", "b", "c.x", "d.x", "d.name")
.hint(Hint.externalHint("hint1"))
.from("SampleEntity")
.where(new And().eq("c.x", "hoge").eq("a", 1L));
REFER句について
EQLにおいて、基本的にはSQLにおけるJOIN句を明示的に記述する必要はありません。あらかじめEntity定義にて定義される参照プロパティを用い、.(ドット)区切りで指定することで参照先のプロパティを指定可能です。
たとえば、EmployeeエンティティとDepartmentエンティティが定義され、Employeeの参照プロパティ (プロパティ名: department) として、Departmentエンティティへの参照が定義される場合、
SELECT job, ename, department.dname FROM Employee
WHERE job = 'SALESMAN' AND sal > 1000
AND department.loc in('CHICAGO', 'BOSTON')
と、department.dnameと指定することにより、Departmentのdnameプロパティを指定可能です。 この場合、結合条件としては、各Entityのプライマリキーであるoidが結合キーとなります。 結合条件にoidに加えて、別プロパティも指定したい場合、REFER句を利用します。
SELECT job, ename, department.dname FROM Employee
REFER department ON department.deptno < 100
WHERE job = 'SALESMAN' AND sal > 1000
AND department.loc in('CHICAGO', 'BOSTON')
上記の場合、
oidによる結合に加えて、 department.deptno < 100
が結合条件として適用されます。
また、REFER句においては、そのほか参照先を結合するためのいくつかのオプションを指定可能です。
AS OF句では、Entityをバージョン管理している場合、参照先のEntityのどの時点のバージョンを結合して取得するかを指定します。
-
AS OF NOW
現時点の最新バージョンを取得します。
SELECT job, ename, department.dname FROM Employee REFER department AS OF NOW WHERE job = 'SALESMAN' AND sal > 1000
-
AS OF UPDATE TIME
登録、更新時のバージョンを取得します。
SELECT job, ename, department.dname FROM Employee REFER department AS OF UPDATE TIME WHERE job = 'SALESMAN' AND sal > 1000
-
AS OF <value expression>
バージョンを明示的に指定するvalue expressionを指定します。 バージョン管理方式がNumberbase、Statebaseの場合、バージョン番号を指定します。
SELECT job, ename, department.dname FROM Employee REFER department AS OF 3 WHERE job = 'SALESMAN' AND sal > 1000
Timebase、SimpleTimebaseの場合、時点を示す日時を指定します。 たとえば、入社日項目hiredateを持っている場合、
SELECT job, ename, department.dname FROM Employee REFER department AS OF hiredate WHERE job = 'SALESMAN' AND sal > 1000
と指定可能です。
LIMIT句について
検索結果の取得行数を指定可能です。
SELECT job, ename, department.dname FROM Employee
LIMIT 100
OFFSET指定は開始位置を指定します。 0を指定した場合は先頭から開始(未指定を同じ)となります。
SELECT job, ename, department.dname FROM Employee
LIMIT 100 OFFSET 1000
Subqueryについて
Subqueryは、IN条件に利用可能です。FROM句への指定はサポートしていません。
また、単一値を返却するSubqueryはScalar subqueryとして利用可能です。Scalar subqueryはValueExpressionと定義されるので、SELECT項目、検索条件の比較項目などとして利用可能です。 詳細はScalar Subqueryの説明を参照ください。
2.2. Value Expression
単一の値を表す要素です。 具体的には、リテラル値、Entityのプロパティ、関数、演算結果などです。 Value Expressionを構成するためのクラス群はorg.iplass.mtp.entity.query.valueパッケージ以下に存在します。
-123
name
(10 + sals) * 0.2
YEAR(dateTimeValue)
Literal val = new Literal(-123);
EntityField val = new EntityField("name");
//(10 + sals) * 0.2
ValueExpression val = new Term(
new ParenValue(
new Polynomial(new Literal(10)).add(new EntityField("sals"))))
.mul(new Literal(0.2));
Function val = new Function("YEAR", new EntityField("dateTimeValue"));
構文
- <value expression> ::=
-
<polynomial> | <term> | <minus sign> | <paren value>
- <polynomial> ::=
-
<value expression> {"+" | - <value expression>}*
- <term> ::=
-
<value expression> {"*" | / <value expression>}*
- <minus sign> ::=
-
- <paren value>
- <paren value> ::=
-
<primary value> | ( <value expression> )
- <primary value> ::=
-
<aggregate> | <array value> | <case> | <entity field> | <function> | <cast> | <literal> | <scalar subquery> | <window function>
- "<aggregate>" ::=
-
{AVG | MAX | MEDIAN | MIN | MODE | STDDEV_POP | STDDEV_SAMP | SUM | VAR_POP | VAR_SAMP ( <value expression> )} | {COUNT( [DISTINCT] [<value expression>] )} | {LISTAGG( [DISTINCT] <value expression> [,<string literal>]) [<within group spec>]}
- <within group spec> ::=
-
WITHIN GROUP( ORDER BY <sort spec> {,<sort spec>}*)
- <array value> ::=
-
"ARRAY[" <value expression> {,<value expression>}* "]"
- "<case>" ::=
-
CASE WHEN "<condition>" THEN <value expression> {WHEN "<condition>" THEN <value expression>}* [ELSE <value expression>] END
- "<entity field>" ::=
-
<property name> | <reference>.<property name> | <correlated entity field>
- <reference> ::=
-
<reference name>{.<reference name>}*
- <correlated entity field> ::=
-
.+{THIS | <entity field> | <reference>}
- "<function>" ::=
-
{<function name>()} | {<function name>( <value expression> {,<value expression>}* )}
- <function name> ::=
-
REPLACE | UPPER | LOWER | CONCAT | SUBSTR | INSTR | CHAR_LENGTH | MOD | SQRT | POWER | ABS | CEIL | FLOOR | ROUND | TRUNCATE | SIN | COS | TAN | ASIN | ACOS | ATAN | ATAN2 | YEAR | MONTH | DAY | HOUR | MINUTE | SECOND | DATE_ADD | DATE_DIFF | CURRENT_DATE | CURRENT_TIME | CURRENT_DATETIME | LOCALTIME
- "<cast>" ::=
-
CAST( <value expression> AS <data type> )
- <data type> ::=
-
BOOLEAN | STRING | INTEGER | FLOAT | DECIMAL | DATETIME | DATE | TIME | SELECT
- "<scalar subquery>" ::=
- "<window function>" ::=
-
<window function type> OVER( [<window partition by clause>] [<window order by clause>] )
- <window function type> ::=
-
{ROW_NUMBER | RANK | DENSE_RANK | PERCENT_RANK | CUME_DIST ()} | <aggregate>
- <window partition by clause> ::=
-
PARTITION BY <value expression> {,<value expression>}*
- <window order by clause> ::=
-
ORDER BY <sort spec> {,<sort spec>}*
- "<literal>" ::=
-
<boolean literal> | <string literal> | <integer literal> | <float literal> | <decimal literal> | <datetime literal> | <date literal> | <time literal> | <select value literal> | NULL
- <boolean literal> ::=
-
TRUE | FALSE
- <string literal> ::=
-
'""文字列""'
- <integer literal> ::=
-
""整数値""[i|I]
- <float literal> ::=
-
""浮動小数点値""[f|F]
- <decimal literal> ::=
-
""固定小数点値""{g|G}
- <datetime literal> ::=
-
'""yyyy-MM-dd HH:mm:ss.SSSフォーマットの日時""'{m|M}
- <date literal> ::=
-
'""yyyy-MM-ddフォーマットの日付""'{d|D}
- <time literal> ::=
-
'""HH:mm:ssフォーマットの時間""'{t|T}
- <select value literal> ::=
-
'""SelectValueのvalue""'{s|S}
- <entity name> ::=
-
""Entityの定義名""
- <property name> ::=
-
""Entityプロパティの定義名""
- <reference name> ::=
-
""Entityの参照プロパティの定義名""
Entity Field
<entity field>はEntityに定義されるプロパティの値を表現する要素です。 Entity定義のプロパティ名を指定します。
name
また、 [参照プロパティ名].[参照先Entityのプロパティ名]
のように、.(ドット)区切りで指定することにより参照先のEntityのプロパティの値を取得・指定可能です。
groups.name
LongText型、Binary型のプロパティは<select clause>の項目としてのみ指定可能です。 <where clause>、<having clause>での条件として利用、また演算、関数を適用した場合の動作は不定です。 |
相関サブクエリを利用する場合、 <correlated entity field>形式にて外側クエリとの結合条件を指定可能です。 外側サブクエリの<entity field>を指定する際には、先頭に.(ドット)を付与します。<correlated entity field>はsubqueryのON句でのみ利用可能です。 詳細はScalar Subqueryの説明を参照ください。
EQLを表現するクラスを利用して生成する場合、 org.iplass.mtp.entity.query.value.primary.EntityField を利用します。
EntityField prop = new EntityField("intProp");
EntityField referenceEntityProp = new EntityField("refProp.strProp");
EntityField correlateProp = new EntityField(".this");
Literal
<literal>はリテラル値を表現する要素です。 EQLで表現可能なリテラル値は以下のものです。
型 | java型 | 説明 |
---|---|---|
boolean |
java.lang.Boolean |
bool値を表します。 EQL表現上、true もしくは falseです。また、case-insensitiveです。 EQL表現例
|
string |
java.lang.String |
文字列を表します。 EQL表現上、'(シングルクォーテーション)で囲まれた文字列で表現します。 文字列中に’を利用したい場合は、''とシングルクォーテーションを重ねることによりエスケープします。 EQL表現例
|
integer |
java.lang.Long |
整数値を表します。 java上ではLong値として扱います。 EQL表現上、数値表現のサフィックスとして、Iもしくはiを指定し整数であることを明示的に示すことも可能です。 EQL表現例
|
float |
java.lang.Double |
浮動小数点値を表します。 java上ではDouble値として扱います。 EQL表現上、数値表現のサフィックスとして、Fもしくはfを指定し浮動小数点であることを明示的に示すことも可能です。また、指数表現もサポートします。 EQL表現例
|
decimal |
java.math.BigDecimal |
固定小数点値を表します。 EQL表現上、数値表現のサフィックスとして、Gもしくはgを指定します。 EQL表現例
|
datetime |
java.sql.Timestamp |
ミリ秒精度の日時を表します。 EQL表現上、'yyyy-MM-dd HH:mm:ss.SSS'、もしくは、タイムゾーン指定する場合’yyyy-MM-dd HH:mm:ss.SSSXXX’形式の文字列とサフィックスとしてMもしくはmを指定します。 タイムゾーン指定がない場合は、テナントに設定されているタイムゾーンと判断します。 EQL表現例
|
date |
java.sql.Date |
日付を表します。 EQL表現上、'yyyy-MM-dd’形式の文字列とサフィックスとしてDもしくはdを指定します。 EQL表現例
|
time |
java.sql.Time |
時間を表します。 EQL表現上、'HH:mm:ss’形式の文字列とサフィックスとしてTもしくはtを指定します。 EQL表現例
|
select |
org.iplass.mtp. |
SelectValueを表現します。 EQL表現上、SelectValueのvalueを文字列して指定しサフィックスとしてSもしくはsを指定します。 EQL表現例
|
null |
null |
null値を表現します。 EQL表現上、nullで表現します。また、case-insensitiveです。 バックエンドのDBによっては、null値と''(空文字)の区別がない場合があります。 EQL表現例
|
Function
<function>は単一値(単一行)を対象とする関数を表現する要素です。
EQLを表現するクラスを利用して生成する場合、 org.iplass.mtp.entity.query.value.primary.Function を利用します。
Function val = new Function("YEAR", new EntityField("dateTimeValue"));(1)
//SELECT name, YEAR(dateTimeValue), DATE_ADD(dateTimeValue, 3, 'DAY')
// FROM someEntity WHERE ABS(someNumProp) > 3
Query q = new Query()
.select(
new EntityField("name"),
new Function("YEAR", new EntityField("dateTimeValue")),(1)
new Function("DATE_ADD",
new EntityField("dateTimeValue"),
new Literal(3L), new Literal("DAY")))(1)
.from("someEntity")
.where(new Greater(new Function("ABS",
new EntityField("someNumProp")), new Literal(3L)));(1)
1 | 第一引数で関数名、第二引数以降で関数の引数を指定します。 |
EQL上表現可能な関数とその引数の説明を以下に示します。
関数 | 返却型 | 説明 | ||
---|---|---|---|---|
REPLACE |
string |
REPLACE(target, from, to) targetの文字列中のfromで表現される文字列をtoに置換します。 EQL表現例
|
||
UPPER |
string |
UPPER(target) targetの文字列を大文字変換します。 EQL表現例
|
||
LOWER |
string |
LOWER(target) targetの文字列を小文字変換します。 EQL表現例
|
||
CONCAT |
string |
CONCAT(target1, target2) target1とtarget2の文字列同士を結合します。 EQL表現例
|
||
SUBSTR |
string |
SUBSTR(target, beginIndex, length) targetの文字列から文字を切り出します。先頭から切り出す場合beginIndexは1です。 EQL表現例
|
||
INSTR |
integer |
INSTR(target, matchStr) matchStrで指定される文字列がtargetの文字列内において、最初に出現したindexを返します。なお返却される値は、先頭から一致した場合は1が返却されます。 EQL表現例
|
||
CHAR_LENGTH |
integer |
CHAR_LENGTH(target) targetで指定される文字列の長さを取得します。 EQL表現例
|
関数 | 返却型 | 説明 | ||
---|---|---|---|---|
MOD |
integer / float / decimal |
MOD(num1, num2) 剰余の計算(num1をnum2で割った余り)を行います。 引数の数値の型により返却される型は異なります。 EQL表現例
|
||
SQRT |
float |
SQRT(num) 平方根を計算します。 EQL表現例
|
||
POWER |
integer / float / decimal |
POWER(base, exp) 累乗(冪乗)を計算します。 引数の数値の型により返却される型は異なります。 EQL表現例
|
||
ABS |
integer / float / decimal |
ABS(num) 絶対値を計算します。 引数の数値の型により返却される型は異なります。 EQL表現例
|
||
CEIL |
integer |
CEIL(num) 小数部を切り上げします。 EQL表現例
|
||
FLOOR |
integer |
FLOOR(num) 小数部を切り下げします。 EQL表現例
|
||
ROUND |
integer / decimal |
ROUND(num, decimalPlace) numをdecimalPlaceの小数点以下の桁数で四捨五入します(ただし、numがfloat型の場合は銀行丸め処理します)。 EQL表現例
|
||
TRUNCATE |
integer / decimal |
TRUNCATE(num, decimalPlace) numをdecimalPlaceの小数点以下の桁数で切り捨てします。 EQL表現例
|
||
SIN |
float |
SIN(num) サインを計算します。 EQL表現例
|
||
COS |
float |
COS(num) コサインを計算します。 EQL表現例
|
||
TAN |
float |
TAN(num) タンジェントを計算します。 EQL表現例
|
||
ASIN |
float |
ASIN(num) アークサインを計算します。 EQL表現例
|
||
ACOS |
float |
ACOS(num) アークコサインを計算します。 EQL表現例
|
||
ATAN |
float |
ATAN(num) アークタンジェントを計算します。 EQL表現例
|
||
ATAN2 |
float |
ATAN2(num1, num2)
EQL表現例
|
関数 | 返却型 | 説明 | ||
---|---|---|---|---|
YEAR |
integer |
YEAR(datetime) datetimeで指定されるdate型、datetime型の年を取得します。 EQL表現例
|
||
MONTH |
integer |
MONTH(datetime) datetimeで指定されるdate型、datetime型の月(1~12)を取得します。 EQL表現例
|
||
DAY |
integer |
DAY(datetime) datetimeで指定されるdate型、datetime型の日(1~31)を取得します。 EQL表現例
|
||
HOUR |
integer |
HOUR(datetime) datetimeで指定されるdate型、datetime型、time型の時(0~23)を取得します。 EQL表現例
|
||
MINUTE |
integer |
MINUTE(datetime) datetimeで指定されるdate型、datetime型、time型の分(0~59)を取得します。 EQL表現例
|
||
SECOND |
integer |
SECOND(datetime) datetimeで指定されるdate型、datetime型、time型の秒(0~59)を取得します。 EQL表現例
|
||
DATE_ADD |
datetime |
DATE_ADD(datetime, addVal, unit) datetimeで指定されるdate型、datetime型、time型にaddValの値を加算します。加算する単位はunitで指定します。 unitには’YEAR','MONTH','DAY','HOUR','MINUTE','SECOND’を指定可能です。 EQL表現例
|
||
DATE_DIFF |
integer |
DATE_DIFF(unit, datetime1, datetime2) datetime1とdatetime2の差分をunitの単位で取得します。 datetime1の方が大きい場合、結果は負の値が返却されます。 unitには’YEAR','MONTH','DAY','HOUR','MINUTE','SECOND’を指定可能です。 EQL表現例
|
||
CURRENT_DATE |
date |
CURRENT_DATE() 現在の日付(年月日)を取得します。 EQL表現例
|
||
CURRENT_TIME |
time |
CURRENT_TIME() 現在の時刻を取得します。 EQL表現例
|
||
CURRENT_DATETIME |
datetime |
CURRENT_DATETIME() 現在の日時を取得します。 EQL表現例
|
||
LOCALTIME |
datetime |
LOCALTIME(datetime) 引数のdatetime(日時)をテナントに設定されたローカル時間を示す日時に変換します。 EQL表現例
|
Cast
<cast>は値のキャストを行う関数です。
CAST( value AS dataType )
valueの値をdataTypeで指定される型に変換します。 dataTypeには以下の<literal>の型を指定可能です。
-
BOOLEAN
-
STRING
-
INTEGER
-
FLOAT
-
DECIMAL
-
DATETIME
-
DATE
-
TIME
-
SELECT
CAST(10.5 AS STRING)
EQLを表現するクラスを利用して生成する場合、 org.iplass.mtp.entity.query.value.primary.Cast を利用します。
Cast castVal = new Cast(new EntityField("intProp"), PropertyDefinitionType.STRING);
Aggregate Function
<aggregate>は複数行を集計するための集計関数を表現する要素です。 集計関数はクエリにおいて、<group by clause>を利用して集計単位を制御することも可能です。
EQLを表現するクラスを利用して生成する場合、 org.iplass.mtp.entity.query.value.aggregate パッケージ配下のクラスを利用します。
Avg avg = new Avg("propValue");
//SELECT category, COUNT(), AVG(amount) FROM someEntity GROUP BY category
Query q = new Query()
.select(
"category",
new Count(),
new Avg("amount"))
.from("someEntity")
.groupBy("category");
EQL上表現可能な集計関数とその引数の説明を以下に示します。
関数 | 返却型 | 説明 | ||
---|---|---|---|---|
AVG |
float |
AVG(num) numで示される数値を集計し平均を算出します。 EQL表現例
|
||
COUNT |
integer |
COUNT(target) targetの値がnullではない行数をカウントします。 EQL表現例
|
||
LISTAGG |
string |
LISTAGG(target) targetの値を文字列として連結します。
EQL表現例
|
||
MAX |
integer / float / decimal |
MAX(num) numで示される数値を集計し最大値を取得します。 引数の数値の型により返却される型は異なります。 EQL表現例
|
||
MEDIAN |
integer / float / decimal |
MEDIAN(num) numで示される数値を集計し中央値を取得します。 引数の数値の型により返却される型は異なります。
EQL表現例
|
||
MIN |
integer / float / decimal |
MIN(num) numで示される数値を集計し最小値を取得します。 引数の数値の型により返却される型は異なります。 EQL表現例
|
||
MODE |
integer / float / decimal |
MODE(num) numで示される数値を集計し最頻値を取得します。 引数の数値の型により返却される型は異なります。
EQL表現例
|
||
STDDEV_POP |
float |
STDDEV_POP(num) numで示される数値を集計し母集団標準偏差を算出します。 EQL表現例
|
||
STDDEV_SAMP |
float |
STDDEV_SAMP(num) numで示される数値を集計し標本標準偏差を算出します。 EQL表現例
|
||
SUM |
integer / float / decimal |
SUM(num) numで示される数値を集計し合計値を取得します。 引数の数値の型により返却される型は異なります。 EQL表現例
|
||
VAR_POP |
float |
VAR_POP(num) numで示される数値を集計し母集団分散を算出します。 EQL表現例
|
||
VAR_SAMP |
float |
VAR_SAMP(num) numで示される数値を集計し標本分散を算出します。 EQL表現例
|
Window Function
<window function>はSQLにおけるWindow関数と同様、結果セットを切り出した領域に集約関数を適用できる関数を表現する要素です。
集約範囲、順番を指定する場合はOVER句(PARTITION BYおよび ORDER BY)によって指定します。
次のようなEntityデータがある場合、
empNo | dept | amount |
---|---|---|
1 |
A |
10 |
2 |
A |
20 |
3 |
B |
50 |
4 |
B |
10 |
5 |
C |
30 |
以下のEQL例はamountをdeptNo単位での合計した値を各行に出力します。
SELECT dept, SUM(amount) OVER(PARTITION BY dept) FROM sample
出力結果は以下です。
dept | SUM(amount) OVER( … ) |
---|---|
A |
30 |
A |
30 |
B |
60 |
B |
60 |
C |
30 |
以下のEQL例はamountをdeptNo単位で、empNoの順で累計した値を各行に出力します。
SELECT dept, empNo, SUM(amount) OVER(PARTITION BY dept ORDER BY empNo) FROM sample
出力結果は以下です。
dept | empNo | SUM(amount) OVER( … ) |
---|---|---|
A |
1 |
10 |
A |
2 |
30 |
B |
3 |
50 |
B |
4 |
60 |
C |
5 |
30 |
MySQL5.7以前ではネイティブにWindow関数がサポートされていません。 DBがMySQL5.7以前の場合でWindow関数を利用したい場合は エミュレーション機能 を利用することが可能です。ただし、エミュレーション機能では、検索結果を一旦メモリ内にすべて展開するため利用には注意が必要です。 Window関数のエミュレーション機能を有効化する場合はStoreServiceの設定が必要です。 |
EQLを表現するクラスを利用して生成する場合、 org.iplass.mtp.entity.query.value.window パッケージ配下のクラスを利用します。
WindowAggregate cumulativeSum = new WindowAggregate(new Sum("amount"))
.partitionBy("category")
.orderBy(new WindowSortSpec("month", SortType.ASC));
//SELECT category, month,
// SUM(amount) OVER(PARTITION BY category ORDER BY month ASC),
// RANK() OVER(ORDER BY amount DESC) FROM someEntity
Query q = new Query().select(
"category",
"month",
new WindowAggregate(new Sum("amount")).partitionBy("category")
.orderBy(new WindowSortSpec("month", SortType.ASC)),
new Rank().orderBy(new WindowSortSpec("amount", SortType.DESC)))
.from("someEntity");
EQL上表現可能なWindow関数とその引数の説明を以下に示します。
関数 | 返却型 | 説明 |
---|---|---|
AVG |
float |
AVG(num) OVER( … ) numで示される数値の平均を算出します。 EQL表現例
|
COUNT |
integer |
COUNT(target) OVER( … ) targetの値がnullではない行数をカウントします。 EQL表現例
|
MAX |
integer / float / decimal |
MAX(num) OVER( … ) numで示される数値の最大値を取得します。 引数の数値の型により返却される型は異なります。 OVER ( … )にはPARTITION BY、ORDER BYを任意で指定可能です。 ORDER BY指定された場合は累積最大値を算出します。 EQL表現例
|
MEDIAN |
integer / float / decimal |
MEDIAN(num) OVER( … ) numで示される数値の中央値を取得します。 OVER ( … )にはPARTITION BYを任意で指定可能です。 引数の数値の型により返却される型は異なります。 EQL表現例
|
MIN |
integer / float / decimal |
MIN(num) OVER( … ) numで示される数値の最小値を取得します。 引数の数値の型により返却される型は異なります。 OVER ( … )にはPARTITION BY、ORDER BYを任意で指定可能です。 ORDER BY指定された場合は累積最小値を算出します。 EQL表現例
|
STDDEV_POP |
float |
STDDEV_POP(num) OVER( … ) numで示される数値を集計し母集団標準偏差を算出します。 OVER ( … )にはPARTITION BY、ORDER BYを任意で指定可能です。 ORDER BY指定された場合は累積の母集団標準偏差を算出します。 EQL表現例
|
STDDEV_SAMP |
float |
STDDEV_SAMP(num) OVER( … ) numで示される数値を集計し標本標準偏差を算出します。 OVER ( … )にはPARTITION BY、ORDER BYを任意で指定可能です。 ORDER BY指定された場合は累積の標本標準偏差を算出します。 EQL表現例
|
SUM |
integer / float / decimal |
SUM(num) OVER( … ) numで示される数値を集計し合計値を取得します。 引数の数値の型により返却される型は異なります。 OVER ( … )にはPARTITION BY、ORDER BYを任意で指定可能です。 ORDER BY指定された場合は累積値を算出します。 EQL表現例
|
VAR_POP |
float |
VAR_POP(num) OVER( … ) numで示される数値を集計し母集団分散を算出します。 OVER ( … )にはPARTITION BY、ORDER BYを任意で指定可能です。 ORDER BY指定された場合は累積の母集団分散を算出します。 EQL表現例
|
VAR_SAMP |
float |
VAR_SAMP(num) OVER( … ) numで示される数値を集計し標本分散を算出します。 OVER ( … )にはPARTITION BY、ORDER BYを任意で指定可能です。 ORDER BY指定された場合は累積の標本分散を算出します。 EQL表現例
|
RANK |
integer |
RANK() OVER( … ) ORDER BYで示される値のよってランク付けをします。 同一ランクの行が2行ある場合は、ランクの値は連続しません。 たとえば、1位の行が2行ある場合は、次のランクの値は3位です。 OVER ( … )にはORDER BYは必ず指定が必要です。PARTITION BYを任意で指定可能です。 EQL表現例
|
DENSE_RANK |
integer |
DENSE_RANK() OVER( … ) ORDER BYで示される値によってランク付けをします。 RANK()関数と異なり、同一ランクの行が2行ある場合でもランクの値は連続します。 たとえば、1位の行が2行ある場合は、次のランクの値は2位です。 OVER ( … )にはORDER BYは必ず指定が必要です。PARTITION BYを任意で指定可能です。 EQL表現例
|
PERCENT_RANK |
float |
PERCENT_RANK() OVER( … ) ORDER BYで示される値によってパーセントランク付けをします。 PERCENT_RANKの戻す値は0から1の範囲です。最初の行は必ず0です。 OVER ( … )にはORDER BYは必ず指定が必要です。PARTITION BYを任意で指定可能です。 EQL表現例
|
CUME_DIST |
float |
CUME_DIST() OVER( … ) ORDER BYで示される値によって累積分布を取得します。 CUME_DISTの戻す値は0から1の範囲です。ただし0を含みません。 OVER ( … )にはORDER BYは必ず指定が必要です。PARTITION BYを任意で指定可能です。 EQL表現例
|
ROW_NUMBER |
integer |
ROW_NUMBER() OVER( … ) ORDER BYで示される値によって行番号を取得します。 先頭行は1が返されます。 OVER ( … )にはORDER BYは必ず指定が必要です。PARTITION BYを任意で指定可能です。 EQL表現例
|
CASE式
<case>は条件分岐を記述可能なValueExpressionです。
CASE WHEN condition1 THEN value1
WHEN condition2 THEN value2 …
ELSE valueDefault END
condition1の条件に一致する場合、value1を返します。 condition2の条件に一致する場合、value2を返します。 すべての条件に一致しない場合は、valueDefaultを返します。
CASE WHEN prop=1 THEN 'ONE' WHEN prop=2 THEN 'TWO' ELSE 'THREE OR MORE' END
CASE WHEN prop IS NULL THEN 0 ELSE prop END
EQLを表現するクラスを利用して生成する場合、 org.iplass.mtp.entity.query.value.controlflow以下のクラスを利用します。
Case caseStatement = new Case().when(new Equals("prop", 1L), new Literal("ONE"))
.when(new Equals("prop", 2L), new Literal("TWO"))
.elseClause(new Literal("THREE OR MORE"));
Scalar Subquery
<scalar subquery>は単一の値を返却するサブクエリです。ScalarSubQueryはValueExpressionとして、条件式、Select項目として利用可能です。 また、ScalarSubQueryはON句を利用して相関サブクエリとして利用することも可能です。相関サブクエリは外側のクエリのそれぞれの行に対してON句の結合条件によってサブクエリを実行します。
( SELECT value FROM entityName WHERE condition … ON .outerJoinItem =innerJoinItem )
ScalarSubQueryはQueryを( )で囲うことでScalarSubQueryと認識されます。 相関サブクエリとして実行する際、ON句において、外側のクエリの結合項目の先頭には.(dot)を付与します。 ON句においては、参照プロパティを指定することも可能です。また、自分自身への参照を表す"THIS"を利用することが可能です。
SELECT propA, (SELECT MAX(propX) FROM SomeEntity) FROM SomeEntity
SELECT propA, (SELECT SUM(propX) FROM CorrelatedEntity
ON .refToCorrelatedEntity.oid=oid)(1)
FROM SomeEntity
1 | 外側クエリのSomeEntityに定義されているrefToCorrelatedEntity参照のoidと、内側QueryのCorrelatedEntity自体のoidで結合条件としている例です。 |
SELECT propA, (SELECT SUM(propX) FROM CorrelatedEntity
ON .refToCorrelatedEntity=THIS)(1)
FROM SomeEntity
1 | 参照プロパティで結合している例です。外側クエリのSomeEntityに定義されているrefToCorrelatedEntity参照と、内側QueryのCorrelatedEntity自身への参照で結合条件としている例です。 |
EQLを表現するクラスを利用して生成する場合、 org.iplass.mtp.entity.query.value.subquery以下のクラスを利用します。
Query q = new Query().select("propA", new ScalarSubQuery(
new Query().select(new Sum("propX")).from("CorrelatedEntity"),
new On(".refToCorrelatedEntity.oid", "oid")))
.from("SomeEntity");
2.3. Condition
条件文を表す要素です。 具体的には、=(イコール)演算子、IN句、またそれらの論理的組み合わせを表現するAND、OR、NOT条件などです。 Conditionを構成するためのクラス群はorg.iplass.mtp.entity.query.conditionパッケージ以下に存在します。
propA=123
name LIKE 'abc%' CI
propX > 30 AND (propY IN ('1', '2', '3') OR propY IS NULL)
Equals eq = new Equals("propA", 123);
Like like = new Like("name", "abc", MatchPattern.PREFIX, CaseType.CI);
//propX > 30 AND (propY IN ('1', '2', '3') OR propY IS NULL)
Condition condition = new And().gt("propX", 30).and(
new Paren(new Or().in("propY", "1", "2", "3").isNull("propY")));
構文
- <condition> ::=
-
<and> | <or> | <not> | <paren>
- <and> ::=
-
<condition> {AND <condition>}*
- <or> ::=
-
<condition> {OR <condition>}*
- <not> ::=
-
NOT <paren>
- <paren> ::=
-
<predicate> | ( <condition> )
- <predicate> ::=
-
<comparison predicate> | <between> | <contains> | <in> | <is not null> | <is null> | <like>
- <comparison predicate> ::=
-
"<value expression>" <comparison operator> "<value expression>"
- <comparison operator> ::=
-
= | > | >= | < | ⇐ | !=
- <between> ::=
-
"<value expression>" BETWEEN "<value expression>" AND "<value expression>"
- "<contains>" ::=
-
CONTAINS('""full text search 検索条件式""')
- "<in>" ::=
-
<simple in> | <row value list in> | <subquery in>
- <simple in> ::=
-
"<value expression>" IN ( "<value expression>" {,"<value expression>"}* )
- <row value list in> ::=
-
( "<value expression>" {,"<value expression>"}\* ) IN ( <row value list> {,<row value list>}* )
- <row value list> ::=
- <subquery in> ::=
-
("<value expression>" {,"<value expression>"}* ) IN "<subquery>"
- <is not null> ::=
-
"<value expression>" IS NOT NULL
- <is null> ::=
-
"<value expression>" IS NULL
- "<like>" ::=
-
"<value expression>" LIKE '""一致パターン文字列""' [CS | CI]
Contains条件文
<contains>はEntityに対する全文検索を行うための条件文です。 Contains条件文の引数として、Luceneクエリ文字列を指定することが可能です。
全文検索はLuceneを利用して行われるため、Contains句を利用する場合は、FulltextSearchServiceの設定にてLuceneの動作環境を整える必要があります。 |
CONTAINS('LuceneQueryExpression')
CONTAINS句がEQLに含まれる場合、次のように動作します。
-
CONTAINS句で指定されるLuceneQueryExpressionがLuceneに対して発行され、Luceneから一致結果のoidが返されます。
-
CONTAINS句はoidを指定するIN句に変換されます。
例:CONTAINS('abc') → oid IN ('12942', '1115', '32107' … )
※このときoidに指定される最大件数はFulltextSearchServiceの設定に依存します。 -
変換されたEQLがRDBに対して発行されます。
CONTAINS('abc')
CONTAINS('abc*')
CONTAINS('"abc" AND "apache"')
EQLを表現するクラスを利用して生成する場合、 org.iplass.mtp.entity.query.condition.predicate.Containsクラスを利用します。
Contains cnt = new Contains("abc*");
In条件文
<in>は、サブクエリもしくは直接指定される複数の項目値と一致するかを判断する条件文です。
valueExp IN (val1, val2, … )
valueExp IN (SELECT field FROM entityName)
OracleではIN句に直接値を指定する場合、デフォルトでは指定可能な件数は1000件までです。この制限を緩和するため、RdbAdapterServiceのenableInPartitioningを有効化することが可能です。 |
<row value list>表現を用いて、複数項目に対するIN条件を構築可能です。
(valueExp1, valueExp2) IN ((val11, val21), (val21, val22), … )
(valueExp1, valueExp2) IN (SELECT field1, field2 FROM entityName)
propA IN('a', 'b', 'c')
propA IN(SELECT propX FROM EntityA)
(propA, propB) IN(('a', 1),('a',2),('b',2))
(propA, propB) IN(SELECT propX, propY FROM EntityA)
EQLを表現するクラスを利用して生成する場合、 org.iplass.mtp.entity.query.condition.predicate.Inクラスを利用します。
In in = new In("propA", "a", "b", "c");
In in = new In("propA", new Query().select("propX").from("EntityA"));
Like条件文
<like>はパターン文字列への一致を判断する条件文です。 %もしくは_をワイルドカードとして指定が可能です。 %、_を通常文字として扱う場合のエスケープ文字は\です。\は\\でエスケープされます。 Case Sensitive、Case Insensitiveで一致するかをそれぞれCS、CI句で指定可能です。
valueExp LIKE 'patternExpression' [CS | CI]
propA LIKE 'abc%'
propA LIKE 'let''s go%' CI
propA LIKE '\\100\_000%'
EQLを表現するクラスを利用して生成する場合、 org.iplass.mtp.entity.query.condition.predicate.Likeクラスを利用します。
パターン文字列を直接指定する場合、%、_、\は自動的にエスケープされないので注意が必要です。MatchPattern指定のコンストラクタ利用を推奨します。 |
Like like = new Like("name", "abc%");
//ユーザーの入力値からパターン文字列を直接指定する場合はエスケープ処理が必要
Like like = new Like("name", StringUtil.escapeEqlForLike(userInputValue) + "%");
//MatchPatternを指定したコンストラクタの場合、コンストラクタ内でエスケープ処理がされる
Like like3 = new Like("name", userInputValue, MatchPattern.PREFIX, CaseType.CI);