Oracle にも OFFSET FETCH が入ってたので Doma の対応コード書いてみた。
仕事で 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 には対応していませんが、ちょっと使う分にはこれで良いかなー。
/* * Copyright 2004-2010 the Seasar Foundation and the Others. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ 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 taedium * */ 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; } }