仕事で Oracle12c を触る機会があって気付いたのですが、Oracle12c から OFFSET FETCH が入ってたようです。
第37回 新しいSQLについて
構文が SQL Server と似た感じですね。
※正確な構文はこちらから SELECT
SQL Server との違いで ORACLE の方が便利そうな箇所は、
- ORDER BY が無くてもOK (普通 ORDER BY 書くけどね)
- OFFSET は省略可 (先頭からN件とる場合)
- FETCH で指定する方法が行数と割合(%)で指定可 (全体の5%とか)
- fetch で with ties を指定すると、最後のデータと同じものは指定行数を超えても含まれる。
SQL Server の方が便利そうな箇所は、
- FETCH を省略可 (先頭N件をスキップして残り全部とる場合)
使うかどうかは置いといて機能的には負けてますね。。
で、Welcome to Doma — Doma 2.0 ドキュメント も使ってたので、12C用の PagingTransformer 書いてみました。
雰囲気動きそうな感じです。percent や with ties には対応していませんが、ちょっと使う分にはこれで良いかなー。
package org.seasar.doma.internal.jdbc.dialect;
import static org.seasar.doma.internal.Constants.ROWNUMBER_COLUMN_NAME;
import org.seasar.doma.internal.jdbc.sql.node.FragmentNode;
import org.seasar.doma.internal.jdbc.sql.node.FromClauseNode;
import org.seasar.doma.internal.jdbc.sql.node.SelectClauseNode;
import org.seasar.doma.internal.jdbc.sql.node.SelectStatementNode;
import org.seasar.doma.internal.jdbc.sql.node.WhereClauseNode;
import org.seasar.doma.jdbc.SqlNode;
@author
public class Oracle12PagingTransformer extends OraclePagingTransformer {
public Oracle12PagingTransformer(long offset, long limit) {
super(offset, limit);
}
@Override
public SqlNode visitSelectStatementNode(SelectStatementNode node, Void p) {
if (processed) {
return node;
}
processed = true;
OrderByClauseNode originalOrderBy = node.getOrderByClauseNode();
OrderByClauseNode orderBy = node.getOrderByClauseNode();
if (originalOrderBy != null) {
orderBy = new OrderByClauseNode(originalOrderBy.getWordNode());
for (SqlNode child : originalOrderBy.getChildren()) {
orderBy.appendNode(child);
}
} else {
orderBy = new OrderByClauseNode("");
}
if (this.offset > 0) {
orderBy.appendNode(new FragmentNode(" offset "));
orderBy.appendNode(new FragmentNode(String.valueOf(this.offset)));
orderBy.appendNode(new FragmentNode(" rows"));
}
if (this.limit > 0) {
orderBy.appendNode(new FragmentNode(" fetch first "));
orderBy.appendNode(new FragmentNode(String.valueOf(this.limit)));
orderBy.appendNode(new FragmentNode(" rows only"));
}
SelectStatementNode result = new SelectStatementNode();
result.setSelectClauseNode(node.getSelectClauseNode());
result.setFromClauseNode(node.getFromClauseNode());
result.setWhereClauseNode(node.getWhereClauseNode());
result.setGroupByClauseNode(node.getGroupByClauseNode());
result.setHavingClauseNode(node.getHavingClauseNode());
result.setOrderByClauseNode(orderBy);
result.setForUpdateClauseNode(node.getForUpdateClauseNode());
result.setOptionClauseNode(node.getOptionClauseNode());
return result;
}
}