1. About EQL
EQL (Entity Query Language) is a query language for searching Entity data stored in iPLAss. It is similar to SELECT statement in SQL language. You could consider Entity and Property as Table and Column in SQL respectively.
The EQL samples is as follow.
SELECT oid, name, mail FROM mtp.auth.User WHERE accountId='scott' ORDER BY name
It is also possible to retrieve value by joining related Entity defined as Reference Property.
SELECT oid, name, groups.name (1)
FROM mtp.auth.User WHERE groups.code='G01'
1 | You could retrieve and specify values of Referenced Entity by means of separating it by .(dot), like [Reference Property name].[Property name of Referenced Entity]. |
Aggregate functions can be used as with SQL.
SELECT job, AVG(sal) FROM Employee GROUP BY job
1.1. Differences from standard SQL
The grammar of EQL is almost equivalent to SELECT statement in standard SQL, there are some differences as follows.
-
About joining between Entities
It is impossible to join Entities between that there is no Reference relationship defined. As for Entity with Reference relationship defined, it is not necessary to describe JOIN clause.
SQL JOIN ExampleSELECT job, ename, Department.dname FROM Employee LEFT OUTER JOIN Department ON Employee.deptno=Department.deptno
EQL JOIN ExampleSELECT job, ename, department.dname FROM Employee (1)
1 Referenced Entity must be defined in advance, with a Reference Property named department. The join(reference) type is always LEFT OUTER JOIN based on the Entity specified in From clause, while it could be specified (OUTER JOIN, INNER JOIN, CROSS JOIN) in SQL.
Also, you should use REFER clause if you want to add item other than the key (oid is the key in Entity) to EQL join condition, while you could specify item other than the key in SQL join condition.
SQL JOIN Example(When specifying item other that the key in join condition)SELECT job, ename, Department.dname FROM Employee LEFT OUTER JOIN Department ON Employee.deptno=Department.deptno AND Department.dname = 'SALES'
EQL JOIN Example(When specifying item other that the key in join condition)SELECT job, ename, department.dname FROM Employee REFER department ON department.dname = 'SALES'
-
Subquery in FROM clause is not supported
In EQL, subquery can not be specified in FROM clause.
-
Set operators is not supported
In EQL, set operator (UNION etc.) is not supported.
-
Alias is not supported
In EQL, alias name can not be assigned to Entity name, Property name.
-
Entity name, Property name are case-sensitive
In EQL, Entity name, Property name are case-sensitive. But EQL expression (SELECT, FROM etc.) is case-insensitive.
-
* (asterisk) expression is not supported
In EQL, wildcard character * (asterisk) can not be specified in SELECT clause. And also * can not be specified in aggregate function, e.g. COUNT. In the case of counting the number of rows,
SELECT COUNT(*) FROM Employee
is not correct,
SELECT COUNT() FROM Employee
Do not use * in expression.
-
Describe join condition with ON clause in correlated subquery
In EQL, in the correlation subquery, the join condition with the outer query is described in the ON clause.
1.2. How to issue EQL
There are two ways to execute EQL. Execute EQL by generating it from String, or using classes that represent EQL.
Issue Query from EQL String
After creating an EQL statement with a String, generate Query instance and issue it via EntityManager. Here is sample code.
import org.iplass.mtp.ManagerLocator;
import org.iplass.mtp.entity.*;
import org.iplass.mtp.entity.query.*;
:
:
//Generate Query instance from EQL String
Query q = new Query("SELECT oid, name, mail FROM mtp.auth.User WHERE accountId='scott' ORDER BY name");
//Issue query via EntityManager
EntityManager em = ManagerLocator.manager(EntityManager.class);
SearchResult<Entity> result = em.searchEntity(q);
In addition, by using PreparedQuery, it is also possible to generate Query instance by passing variables to an EQL template prepared in advance. Here is sample code.
import org.iplass.mtp.ManagerLocator;
import org.iplass.mtp.entity.*;
import org.iplass.mtp.entity.query.*;
:
:
//Generate EQL template in advance
PreparedQuery queryTemplate = new PreparedQuery("SELECT oid, name, mail FROM mtp.auth.User WHERE accountId='${aid}' and name='$s{inputVal}' ORDER BY name");(1)
:
:
//Generate Query instance from PreparedQuery, set a value for parameter aid.
Map<String, Object> bindings = new HashMap<>();
bindings.put("aid", "scott");
bindings.put("inputVal", userInputValue);
Query q = queryTemplate.query(bindings);
//Issue query by using EntityManager
EntityManager em = ManagerLocator.manager(EntityManager.class);
SearchResult<Entity> result = em.searchEntity(q);
1 | You could define parameter like ${parameter name}, replace it with actual value when generating Query. And escape processing can be done by using $s{ … } or $sl{ … } of GroovyTemplate. |
Issue Query from classes that represent EQL
Construct Query by using classes that represent EQL, issue query via EntityManager. Classes that represent EQL are under the package, org.iplass.mtp.entity.query.
Here is sample code.
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. Component Element
The component element for constructing EQL are described as follows. EQL syntax is described by BNF (Backus-Naur form) together.
Description of expression elements that extend BNF.
Extend the following expression elements for BNF. [ ] = Optional element |
2.1. Query
Element that represents an entire EQL statement. Represent the query for Entity. Class for constructing Query is under the package, 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);
Syntax
- <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> ::=
-
""hint expression""
- <from clause> ::=
-
FROM ""Entity definition name""
- "<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 ""number"" [OFFSET ""start offset""]
- "<subquery>" ::=
-
(<query> [ON "<condition>"])
About Hint Comment
By specifying <hint comment>, it is possible to tune search process, such as by means of using an index during Entity search, or DB native hint comment, etc.. Surround <hint comment> with /*+ */, place it immediately after SELECT. You can separate multiple hint expressions by spaces.
EQL supports the following hint expressions.
Hint | Description |
---|---|
bind |
A hint for EQL to specify that literal values are set using binding parameter(PreparedStatement in JDBC) when query is actually issued to DB.
In the above case, 'SALESMAN'、1000、100 are executed as binding parameters. By assigning no_bind hint to the literal value to be bound, it is possible to exclude the literal value from being bound.
In the above case, 1000、100 are executed as binding variables. |
cache |
A hint for caching EQL execution result. Cache Scope and Cache Expiration Time (seconds) can by specified with argument. Cache scope can be set to one of the following.
It can be specified as below. Scope:TRANSACTION,
Scope:GLOBAL、Cache Expiration Time:infinite,
Scope:GLOBAL、Cache Expiration Time:10 minutes,
Scope:GLOBAL_KEEP、Cache Expiration Time:infinite,
Scope:GLOBAL_KEEP、Cache Expiration Time:10 minutes,
Scope:GLOBAL_RELOAD、Reload Interval:10 minutes,
|
fetch_size |
A hint for specifying fetch size(Statement#setFetchSize(int) in JDBC)when issuing query to DB.
|
index |
Explicitly specify to use the Property that specified in argument as an INDEX. The Property specified as INDEX should be set to INDEX, UNIQUE INDEX in Entity definition.
It is possible to separate multiple properties by , (comma). (However, it depends on DB to choose which INDEX to use actually.)
It depends on DB to choose which Property INDEX to use when neither index hint nor no_index hint is specified. |
native |
It is possible to specify hint to be assigned to DB native SQL statement (if DB is RDB) that converted from EQL. Specify native hint as a string argument.
If you want to specify a hint clause for a table (Such as index hint in MySQL etc.), specify the table name as the first argument.
|
no_bind |
A hint for EQL to specify that binding variable (PrepareStatement in JDBC) not be used when actually issuing a query to the DB.
For the sake of specifying a specific EQL to execute without binding when issuing EQL if alwaysBind is set to true, according to the setting of RdbAdapterService. |
no_index |
Exclude Property specified in argument from using as an INDEX alternatives.
It is possible to specify multiple properties separated by , (comma).
It depends on DB to choose which Property INDEX to use when neither index hint nor no_index hint is specified. |
read_only |
If you want to issue the EQL as a read-only transaction, this hint clause can be used. However, if the resultMode of SearchOption in the search call is
|
suppress_warnings |
The hint as an annotation to suppress the output of the EQL warning log. For instance, when executing EQL, the warning log will complain about the INDEX property in search condition not being used. However, this warning is unnecessary when the amount of Entity data is small. For such conditions, the user can suppress these kind of warnings with this hint item.
|
timeout |
specify the timeout of a query (Statement#setQueryTimeout(int) in JDBC). It depends on DB exactly how many seconds to disconnect.
|
And also, it is possible to define hint clause in external property file and load it from that file by specifying key name. The path of property file is defined in QueryService.
Especially when you want to use native hint clause directly, or optimal hint clauses may differ depend on different environment. In this situation, it will be able to manager different hint clauses for each environment.
hint1 = native(q0t0, 'FORCE INDEX(obj_store__USER_ISTR_index_3)')
hint2 = native(q0, 'FORCE INDEX(obj_store_ISTR_index_1)')
:
Specify external hint clause with @hint("key name").
In the environment that above property file is defined.
select /*+ @hint(hint1) */ a, b, c.x, d.x, d.name from SampleEntity where c.x='hoge' and a=1 and b=15
When above EQL is issued, it will be converted to
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
It is possible to get hint class instance by Hint.externalHint(String) when using Query class.
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));
About REFER Clause
Basically it is not necessary to describe JOIN clause explicitly in EQL like in SQL. You can specify Reference Property with separating by . (dot), that defined in Entity definition in advance.
For example, Employee Entity and Department Entity are defined, with a Reference Property named department in Employee that referencing Department Entity.
SELECT job, ename, department.dname FROM Employee
WHERE job = 'SALESMAN' AND sal > 1000
AND department.loc in('CHICAGO', 'BOSTON')
Also, it is possible to specify Property named dname in Department by means of specifying department.dename. The oid defined in each Entity are used as join key in join condition in the above case. Use Refer clause if you want to specify other Property in addition to oid in join condition.
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')
In the above case,
in addition to oid, department.deptno < 100
is applied as a join condition.
Also, there are some options that could be specified in Refer clause when joining with reference target.
AS OF is used to specify which version is used to join with Referenced Entity, when Versioning is enabled for the Entity.
-
AS OF NOW
Get the latest version at the moment.
SELECT job, ename, department.dname FROM Employee REFER department AS OF NOW WHERE job = 'SALESMAN' AND sal > 1000
-
AS OF UPDATE TIME
Get version at the time of inserting or updating.
SELECT job, ename, department.dname FROM Employee REFER department AS OF UPDATE TIME WHERE job = 'SALESMAN' AND sal > 1000
-
AS OF <value expression>
Specify a value expression that explicitly specifies version. Specify version number for Numberbase/Statebase Versioning.
SELECT job, ename, department.dname FROM Employee REFER department AS OF 3 WHERE job = 'SALESMAN' AND sal > 1000
For Timebase/SimpleTimebase, specify the date and time to indicate the time. For example, if there is a hire date item named hiredate,
SELECT job, ename, department.dname FROM Employee REFER department AS OF hiredate WHERE job = 'SALESMAN' AND sal > 1000
can be specified like above.
About Limit Clause
Specify the number of lines for retrieving search results.
SELECT job, ename, department.dname FROM Employee
LIMIT 100
Specify OFFSET for the start position. If 0 is specified, it starts from the beginning (same as unspecified).
SELECT job, ename, department.dname FROM Employee
LIMIT 100 OFFSET 1000
About Subquery
Subquery is possible to be used in the IN condition. It is not supported in FROM clause.
Also, Subquery returns a single value can be used as Scalar subquery. Scalar subquery could be used as such as SELECT item, comparison item in search condition etc. because it is defined as ValueExpression. Please refer to the description in "Scalar subquery".
2.2. Value Expression
An element that represents a single value. Specifically, literal value, Entity Property, function, operation results etc. Classes consist of Value Expression are under the package 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"));
Syntax
- <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>}
※correlated entity field could be used only in ON clause of subquery. - "<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> ::=
-
'""string""'
- <integer literal> ::=
-
""integer value""[i|I]
- <float literal> ::=
-
""value of floating-point number""[f|F]
- <decimal literal> ::=
-
""value of fixed-point number""{g|G}
- <datetime literal> ::=
-
'""datetime format as yyyy-MM-dd HH:mm:ss.SSS""'{m|M}
- <date literal> ::=
-
'""date format as yyyy-MM-dd""'{d|D}
- <time literal> ::=
-
'""time format as HH:mm:ss""'{t|T}
- <select value literal> ::=
-
'""value of SelectValue""'{s|S}
- <entity name> ::=
-
""definition name of Entity""
- <property name> ::=
-
""definition name of Entity Property""
- <reference name> ::=
-
""definition name of Entity Reference Property""
Entity Field
<entity field> is an element that represents the property value defined in the Entity. Specifies the property name of the Entity definition.
name
In addition, you can obtain and specify the value of the property of the referenced entity by specifying it in the format [reference property name].[property name of the referenced entity]
separated by dots.
groups.name
LongText type and Binary type properties can only be specified as <select clause> items. If used as a condition in <where clause> or <having clause>, or if an operation or function is applied, the behavior is undefined. |
When using correlated subqueries, It is possible to specify the join condition with the outer query in the <correlated entity field> format. When specifying the <entity field> of the outer subquery, add a .(dot) to the beginning. <correlated entity field> is only available in ON clause of subquery. See "Scalar Subquery" for details.
When generating by using classes represent EQL, use 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> is a element that represents literal value. Literal value can be used in EQL as follows.
Type | Java type | Description |
---|---|---|
boolean |
java.lang.Boolean |
Represents bool value. true or false in EQL expression. Also, it is case-insensitive. EQL Expression Example
|
string |
java.lang.String |
Represents string. String is surrounded with ' (single quota) in EQL expression. If you want to use ' in string, escape by using two single quotas as ''. EQL Expression Example
|
integer |
java.lang.Long |
Represents value of integer number. Treated as Long value in java. It is possible to explicitly indicate integer number by specifying I or i as a suffix of value expression in EQL expression. EQL Expression Example
|
float |
java.lang.Double |
Represents value of floating-point number. Treated as Double value in java. It is possible to explicitly indicate floating-point number by specifying F or f as a suffix of value expression in EQL expression. Also supports exponential expression. EQL Expression Example
|
decimal |
java.math.BigDecimal |
Represents value of fixed-point number. Specify G or g as a suffix of value expression in EQL expression. EQL Expression Example
|
datetime |
java.sql.Timestamp |
Represents date and time with millisecond precision. Specify a string in the format 'yyyy-MM-dd HH:mm:ss.SSS' or 'yyyy-MM-dd HH:mm:ss.SSSXXX' if timezone is specified, and M or m as a suffix in EQL expression. If there is no timezone specified, timezone that set in Tenant will be determined. EQL Expression Example
|
date |
java.sql.Date |
Represents date. Specify a string in the format 'yyyy-MM-dd' and D or d as a suffix in EQL expression. EQL Expression Example
|
time |
java.sql.Time |
Represents time. Specify a string in the format 'HH:mm:ss' and T or t as a suffix in EQL expression. EQL Expression Example
|
select |
org.iplass.mtp. |
Represents SelectValue. Specify value of SelectValue as a string and S or s as a suffix in EQL expression. EQL Expression Example
|
null |
null |
Represents null value. Represents null in EQL expression. Also, it is case-insensitive. Depending on backend DB, there may be no distinction between null value and ''(empty string). EQL Expression Example
|
Function
<function> is a element that represents function targeting a single value (a single line).
When generating by using classes represent EQL, use 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 | Specify function name with the first argument, arguments after the first one with the arguments of the function. |
Description of functions and arguments can be represent in EQL are as follows.
Function | Type of return value | Description | ||
---|---|---|---|---|
REPLACE |
string |
REPLACE(target, from, to) Replace string represented by from with the string represented by to within the string of target. EQL Expression Example
|
||
UPPER |
string |
UPPER(target) Convert string represented by target to upper case. EQL Expression Example
|
||
LOWER |
string |
LOWER(target) Convert string represented by target to lower case. EQL Expression Example
|
||
CONCAT |
string |
CONCAT(target1, target2) Concatenate string represented by target with the one represented by target2. EQL Expression Example
|
||
SUBSTR |
string |
SUBSTR(target, beginIndex, length) Returns a string that is a substring of the string represented by target. The beginIndex is 1 if you want to start from the beginning. EQL Expression Example
|
||
INSTR |
integer |
INSTR(target, matchStr) Returns the index within the string represented by target of the first occurrence of the string represented by matchStr. Return value is 1 if matches from the beginning. EQL Expression Example
|
||
CHAR_LENGTH |
integer |
CHAR_LENGTH(target) Returns the length of the string represented by target. EQL Expression Example
|
Function | Return type | Description | ||
---|---|---|---|---|
MOD |
integer / float / decimal |
MOD(num1, num2) Computes the remainder (the remainder of dividing num1 by num2). Return type depends on the type of number arguments. EQL Expression Example
|
||
SQRT |
float |
SQRT(num) Computes the square root。 EQL Expression Example
|
||
POWER |
integer / float / decimal |
POWER(base, exp) Computes the power (exponentiation). Return type depends on the type of number arguments. EQL Expression Example
|
||
ABS |
integer / float / decimal |
ABS(num) Computes the absolute value. Return type depends on the type of number arguments. EQL Expression Example
|
||
CEIL |
integer |
CEIL(num) Rounds up to the nearest integer. EQL Expression Example
|
||
FLOOR |
integer |
FLOOR(num) Rounds down the nearest integer. EQL Expression Example
|
||
ROUND |
integer / decimal |
ROUND(num, decimalPlace) Rounds off num to the decimal places specified with decimalPlace.(However, if num is a float type, banker’s rounding is performed). EQL Expression Example
|
||
TRUNCATE |
integer / decimal |
TRUNCATE(num, decimalPlace) Rounds down num to the decimal places specified with decimalPlace.
decimalPlace can be a negative number. For example, if -1 is specified, it will be rounded down to the nearest 10. EQL Expression Example
|
||
SIN |
float |
SIN(num) Computes the sine. EQL Expression Example
|
||
COS |
float |
COS(num) Computes the cosine. EQL Expression Example
|
||
TAN |
float |
TAN(num) Computes the tangent. EQL Expression Example
|
||
ASIN |
float |
ASIN(num) Computes the arcsine. EQL Expression Example
|
||
ACOS |
float |
ACOS(num) Computes the arccosine. EQL Expression Example
|
||
ATAN |
float |
ATAN(num) Computes the arctangent. EQL Expression Example
|
||
ATAN2 |
float |
ATAN2(num1, num2) Computes the arctangent of EQL Expression Example
|
Function | Return type | Description | ||
---|---|---|---|---|
YEAR |
integer |
YEAR(datetime) Gets the year of the date type or datetime type specified with datatime. EQL Expression Example
|
||
MONTH |
integer |
MONTH(datetime) Gets the month (1~12) of the date type or datetime type specified with datetime. EQL Expression Example
|
||
DAY |
integer |
DAY(datetime) Gets the day (1~31) of the date type or datetime type specified with datetime. EQL Expression Example
|
||
HOUR |
integer |
HOUR(datetime) Gets the hour (0~23) of time type, date type or datetime type specified with datetime. EQL Expression Example
|
||
MINUTE |
integer |
MINUTE(datetime) Gets the minute (0~59) of time type, date type or datetime type specified with datetime. EQL Expression Example
|
||
SECOND |
integer |
SECOND(datetime) Gets the second (0~59) of time type, date type or datetime type specified with datetime. EQL Expression Example
|
||
DATE_ADD |
datetime |
DATE_ADD(datetime, addVal, unit) Adds the value specified with addVal to data type, datetime type, time type specified with datetime. The unit to add is specified by unit. unit can be 'YEAR','MONTH','DAY','HOUR','MINUTE','SECOND'. EQL Expression Example
|
||
DATE_DIFF |
integer |
DATE_DIFF(unit, datetime1, datetime2) Gets the difference between datetime1 and datetime2 in units of unit. If datetime1 is larger, the result is a negative value. unit can be 'YEAR', 'MONTH', 'DAY', 'HOUR', 'MINUTE', 'SECOND'. EQL Expression Example
|
||
CURRENT_DATE |
date |
CURRENT_DATE() Gets current date (year / month / day). EQL Expression Example
|
||
CURRENT_TIME |
time |
CURRENT_TIME() Gets the current time. EQL Expression Example
|
||
CURRENT_DATETIME |
datetime |
CURRENT_DATETIME() Gets the current date and time. EQL Expression Example
|
||
LOCALTIME |
datetime |
LOCALTIME(datetime) Converts datetime of the argument to the datetime specified in locale time set in Tenant. EQL Expression Example
|
Cast
<cast> is a function that casts a value.
CAST( value AS dataType )
Convert the value of value to the type specified with dateType. <literal> value could be converted to are listed as follows.
-
BOOLEAN
-
STRING
-
INTEGER
-
FLOAT
-
DECIMAL
-
DATETIME
-
DATE
-
TIME
-
SELECT
CAST(10.5 AS STRING)
When generating by using classes represent EQL, use org.iplass.mtp.entity.query.value.primary.Cast.
Cast castVal = new Cast(new EntityField("intProp"), PropertyDefinitionType.STRING);
Aggregate Function
<aggregate> is a element that represents aggregate function to aggregate multiple rows. Aggregate functions can also control aggregation units by using <group by clause> in query.
When generating by using classes represent EQL, use classes under the package 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");
Description of aggregation functions can be represented and those arguments in EQL are as follows.
Function | Return type | Description | ||
---|---|---|---|---|
AVG |
float |
AVG(num) Calculates the average by aggregating the numbers represented with num. EQL Expression Example
|
||
COUNT |
integer |
COUNT(target) Counts the number of the rows where value of target is not null. EQL Expression Example
|
||
LISTAGG |
string |
LISTAGG(target) Concatenate the target values as a string.
EQL Expression Example
|
||
MAX |
integer / float / decimal |
MAX(num) Aggregates values specified with num and get the maximum one. Return type depends on the type of number argument. EQL Expression Example
|
||
MEDIAN |
integer / float / decimal |
MEDIAN(num) Aggregates values specified with num and get the median. Return type depends on the type of number argument.
EQL Expression Example
|
||
MIN |
integer / float / decimal |
MIN(num) Aggregates values specified with num and get the minimum one. Return type depends on the type of number argument. EQL Expression Example
|
||
MODE |
integer / float / decimal |
MODE(num) Aggregates values specified with num and get the mode. Return type depends on the type of number argument.
EQL Expression Example
|
||
STDDEV_POP |
float |
STDDEV_POP(num) Aggregates values specified with num and calculates the population standard deviation. EQL Expression Example
|
||
STDDEV_SAMP |
float |
STDDEV_SAMP(num) Aggregates values specified with num and calculates the sample standard deviation. EQL Expression Example
|
||
SUM |
integer / float / decimal |
SUM(num) Aggregates values specified with num and gets the sum of values. Return type depends on the type of number argument. EQL Expression Example
|
||
VAR_POP |
float |
VAR_POP(num) Aggregates values specified with num and calculates the population variance. EQL Expression Example
|
||
VAR_SAMP |
float |
VAR_SAMP(num) Aggregates values specified with num and calculates the sample variance. EQL Expression Example
|
Window Function
<window function> is an element that represents a function that can apply an aggregate function to the fields that cut from the result set, similar to the Window function in SQL.
When specifying the aggregation range and order, use the OVER clause (PARTITION BY and ORDER BY).
Here are Entity data as follows,
empNo | dept | amount |
---|---|---|
1 |
A |
10 |
2 |
A |
20 |
3 |
B |
50 |
4 |
B |
10 |
5 |
C |
30 |
The following EQL example outputs the sum of amount in units of deptNo for each row.
SELECT dept, SUM(amount) OVER(PARTITION BY dept) FROM sample
Output are as follows.
dept | SUM(amount) OVER( … ) |
---|---|
A |
30 |
A |
30 |
B |
60 |
B |
60 |
C |
30 |
The following EQL sample output the sum of amount in units of deptNo in order of empNo for each row.
SELECT dept, empNo, SUM(amount) OVER(PARTITION BY dept ORDER BY empNo) FROM sample
Output are as follows.
dept | empNo | SUM(amount) OVER( … ) |
---|---|---|
A |
1 |
10 |
A |
2 |
30 |
B |
3 |
50 |
B |
4 |
60 |
C |
5 |
30 |
Window function is not supported natively before MySQL5.7. If you want to use window function in the DB before MySQL5.7, it is possible by using [.eeonly]#Function Emulation. However, with the emulated function, all search results are temporarily expanded in memory, so you should be careful with it. Settings of StoreService is required if you want to enable the Windows function emulation. |
When generating by using classes represent EQL, use classes under the package 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");
Description of Window functions that can be represent in EQL and those arguments are as follows.
Function | Return type | Description |
---|---|---|
AVG |
float |
AVG(num) OVER( … ) Calculates the average of the values specified with num. EQL Expression Example
|
COUNT |
integer |
COUNT(target) OVER( … ) Counts the number of rows where the value of target is not null. EQL Expression Example
|
MAX |
integer / float / decimal |
MAX(num) OVER( … ) Gets the maximum value of the values represents by num. Return type depends on the argument type. PARTITION BY and ORDER BY can be specified optionally in OVER ( … ). If ORDER BY is specified, the cumulative maximum is calculated. EQL Expression Example
|
MEDIAN |
integer / float / decimal |
MEDIAN(num) OVER( … ) Get the median of values represented by num. PARTITION BY can be specified optionally in OVER ( … ). Return type depends on the type of argument value. EQL Expression Example
|
MIN |
integer / float / decimal |
MIN(num) OVER( … ) Gets the minimum value of the values specified with num. Return type depends on the type of argument value. PARTITION BY, ORDER BY can be specified optionally in OVER (…). If ORDER BY is specified, the cumulative minimum is calculated. EQL Expression Example
|
STDDEV_POP |
float |
STDDEV_POP(num) OVER( … ) Aggregates values specified with num and calculates the population standard deviation. PARTITION BY, ORDER BY can be specified optionally in OVER ( … ). If ORDER BY is specified, the cumulative population standard deviation is calculated. EQL Expression Example
|
STDDEV_SAMP |
float |
STDDEV_SAMP(num) OVER( … ) Aggregates values specified with num and calculates the sample standard deviation. PARTITION BY, ORDER BY can be specified optionally in OVER ( … ). If ORDER BY is specified, the cumulative sample standard deviation is calculated. EQL Expression Example
|
SUM |
integer / float / decimal |
SUM(num) OVER( … ) Aggregates values specified with num and calculates the sum of values. Return type depends on the type of argument value. PARTITION BY, ORDER BY can be specified optionally in OVER ( … ). If ORDER BY is specified, cumulative value is calculated. EQL Expression Example
|
VAR_POP |
float |
VAR_POP(num) OVER( … ) Aggregates values specified with num and calculates the population variance. PARTITION BY, ORDER BY can be specified optionally in OVER ( … ). If ORDER BY is specified, the cumulative population variance is calculated. EQL Expression Example
|
VAR_SAMP |
float |
VAR_SAMP(num) OVER( … ) Aggregates values specified with num and calculates the sample variance. PARTITION BY, ORDER BY can be specified optionally in ORDER ( … ). If ORDER BY is specified, the cumulative sample variance is calculated. EQL Expression Example
|
RANK |
integer |
RANK() OVER( … ) Assigns rank values according to values specified by ORDER BY. If there are two rows with the same rank value, rank values are not consecutive. For example, there are two rows with rank value 1, the next rank value will be 3. ORDER BY must be specified in OVER ( … ). PARTITION BY is optional. EQL Expression Example
|
DENSE_RANK |
integer |
DENSE_RANK() OVER( … ) Assigns rank values according to values specified by ORDER BY. If there are two rows with the same rank value, whether rank values are consecutive or not depends on RANK() function. For example, there are two rows with rank value 1, the next rank value will be 2. ORDER BY must be specified in ORDER ( … ). PARTITION BY is optional. EQL Expression Example
|
PERCENT_RANK |
float |
PERCENT_RANK() OVER( … ) Assigns percent rank values according to values specified by ORDER BY. The return value of PERCENT_RANK is range from 0 to 1. The first line must be 0. ORDER BY must be specified in OVER ( … ). PARTITION BY is optional. EQL Expression Example
|
CUME_DIST |
float |
CUME_DIST() OVER( … ) Gets the cumulative distribution according to values specified by ORDER BY. The return value of CUME_DIST is range from 0 to 1. However, 0 is not included. ORDER BY is must be specified in OVER ( … ). PARTITION BY is optional. EQL Expression Example
|
ROW_NUMBER |
integer |
ROW_NUMBER() OVER( … ) Gets line numbers according to values specified by ORDER BY. The value of the first line is 1. ORDER BY must be specified in OVER ( … ). PARTITION BY is optional. EQL Expression Example
|
CASE Expression
<case> is a ValueExpression that can describe conditional branch.
CASE WHEN condition1 THEN value1
WHEN condition2 THEN value2 …
ELSE valueDefault END
If condition1 matches, return value1. If condition2 matches, return value2. If all conditions do not match, return 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
Generate by using classes represent EQL. Use classes under the package 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> is a subquery that returns a single value. ScalarSubQuery can be used as ValueExpression, conditional expression, SELECT item. Also, ScalarSubQuery can be used with ON clause as correlated subquery. Correlated subquery executes for each row of outer Query with join condition in ON clause.
( SELECT value FROM entityName WHERE condition … ON .outerJoinItem =innerJoinItem )
ScalarSubQuery is recognized by surrounding Query with ( ). When executing correlated subquery, assign .(dot) to the start of the outer join item in ON clause. It is possible to specify Reference Property in ON clause. Also, "THIS" can be used to represent a reference to itself.
SELECT propA, (SELECT MAX(propX) FROM SomeEntity) FROM SomeEntity
SELECT propA, (SELECT SUM(propX) FROM CorrelatedEntity
ON .refToCorrelatedEntity.oid=oid)(1)
FROM SomeEntity
1 | In this example, the join condition is the Reference Property refToCorrelatedEntity defined in SomeEntity in outer Query and the oid of CorrelatedEntity itself in the inner Query. |
SELECT propA, (SELECT SUM(propX) FROM CorrelatedEntity
ON .refToCorrelatedEntity=THIS)(1)
FROM SomeEntity
1 | Joining by Reference Property. In this example, the join condition is refToCorrelatedEntity defined in SomeEntity in outer Query and the oid of CorrelatedEntity itself in the inner Query. |
When generating by using classes represent EQL, use classes under the package 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
Elements represent condition statement. Specifically, elements that represent =(equal) operator, IN clause, and conditions like AND, OR, NOT represent combination of them. Use classes under the package org.iplass.mtp.entity.query.condition to construct 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")));
Syntax
- <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 search condition expression""')
- "<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 '""match pattern string""' [CS | CI]
Contains Conditional Statement
<contains> is a conditional statement for executing full-text search to Entity. Lucene query string could be specified as argument of Contains conditional statement.
Because full-text search is performed by using Lucene, when using Contains clause, it is necessary to prepare the operating environment for Lucene with settings of FulltextSearchService. |
CONTAINS('LuceneQueryExpression')
If CONTAINS clause is included in EQL, works as follows.
-
LuceneQueryExpression specified in CONTAINS clause is issued for Lucene, matching oid are returned by Lucene.
-
CONTAINS is converted to IN clause that specifies oid.
Eg. CONTAINS('abc') → oid IN ('12942', '1115', '32107' … )
※At this time, the maximum number specified in oid depends on the setting of FulltextSearchService. -
Converted EQL is issued to RDB.
CONTAINS('abc')
CONTAINS('abc*')
CONTAINS('"abc" AND "apache"')
When generating by using classes represent EQL, use classes under the package org.iplass.mtp.entity.query.condition.predicate.Contains.
Contains cnt = new Contains("abc*");
In Conditional Statement
<in> is a statement that determines whether matches subquery or the multiple values specified directly.
valueExp IN (val1, val2, … )
valueExp IN (SELECT field FROM entityName)
In Oracle, when specifying values directly in IN clause, the maximum number can be specified is 1000 by default. To relax restriction, you can enable enableInPartitioning of RdbAdapterService. |
It is possible to construct IN conditions for multiple items using <row value list> expression.
(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)
When generating by using classes represent EQL, use class 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 Conditional Statement
<like> is a conditional statement that determines whether pattern string matches. % or _ can be specified as wildcard. Escapes with \ when treating % or _ as a normal character. \ is escaped by using \\. CS and CI clauses specify whether matches in Case Sensitive and Case Insensitive.
valueExp LIKE 'patternExpression' [CS | CI]
propA LIKE 'abc%'
propA LIKE 'let''s go%' CI
propA LIKE '\\100\_000%'
When generating by using classes represent EQL, use class org.iplass.mtp.entity.query.condition.predicate.Like.
When specifying pattern string directly, be careful with %, _, \, as they are not escaped automatically. Using the constructor with MatchPattern specified is recommended. |
Like like = new Like("name", "abc%");
//When specifying pattern string directly from user input value, escaping is required.
Like like = new Like("name", StringUtil.escapeEqlForLike(userInputValue) + "%");
//When using the constructor with MatchPattern specified, escaping is done in the constructor.
Like like3 = new Like("name", userInputValue, MatchPattern.PREFIX, CaseType.CI);