change the Oracle select to use OFFSET...FETCH

This commit is contained in:
zhangyongding
2026-01-22 08:35:52 +08:00
parent 74632b3aec
commit 18d53180f6
2 changed files with 17 additions and 73 deletions
+13 -69
View File
@@ -6,7 +6,6 @@ package sqlbuilder
import (
"fmt"
"reflect"
"strings"
"github.com/huandu/go-clone"
)
@@ -374,8 +373,6 @@ func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
buf := newStringBuilder()
sb.injection.WriteTo(buf, selectMarkerInit)
oraclePage := flavor == Oracle && (len(sb.limitVar) > 0 || len(sb.offsetVar) > 0)
if sb.cteBuilderVar != "" {
buf.WriteLeadingString(sb.cteBuilderVar)
sb.injection.WriteTo(buf, selectMarkerAfterWith)
@@ -388,51 +385,11 @@ func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
buf.WriteString("DISTINCT ")
}
if oraclePage {
var selectCols = make([]string, 0, len(sb.selectCols))
for i := range sb.selectCols {
cols := strings.SplitN(sb.selectCols[i], ".", 2)
if len(cols) == 1 {
selectCols = append(selectCols, cols[0])
} else {
selectCols = append(selectCols, cols[1])
}
}
buf.WriteStrings(selectCols, ", ")
} else {
buf.WriteStrings(sb.selectCols, ", ")
}
buf.WriteStrings(sb.selectCols, ", ")
}
sb.injection.WriteTo(buf, selectMarkerAfterSelect)
if oraclePage {
if len(sb.selectCols) > 0 {
buf.WriteLeadingString("FROM (SELECT ")
if sb.distinct {
buf.WriteString("DISTINCT ")
}
var selectCols = make([]string, 0, len(sb.selectCols)+1)
selectCols = append(selectCols, "ROWNUM r")
for i := range sb.selectCols {
cols := strings.SplitN(sb.selectCols[i], ".", 2)
if len(cols) == 1 {
selectCols = append(selectCols, cols[0])
} else {
selectCols = append(selectCols, cols[1])
}
}
buf.WriteStrings(selectCols, ", ")
buf.WriteLeadingString("FROM (SELECT ")
buf.WriteStrings(sb.selectCols, ", ")
}
}
tableNames := sb.TableNames()
if len(tableNames) > 0 {
@@ -562,34 +519,21 @@ func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
}
case Oracle:
if oraclePage {
buf.WriteString(") ")
// It's required to make OFFSET...FETCH work.
if len(sb.offsetVar) > 0 {
buf.WriteLeadingString("OFFSET ")
buf.WriteString(sb.offsetVar)
buf.WriteString(" ROWS")
}
if len(sb.tables) > 0 {
buf.WriteStrings(sb.tables, ", ")
if len(sb.limitVar) > 0 {
if len(sb.offsetVar) == 0 {
buf.WriteLeadingString("OFFSET 0 ROWS")
}
buf.WriteString(") WHERE ")
if len(sb.limitVar) > 0 {
buf.WriteString("r BETWEEN ")
if len(sb.offsetVar) > 0 {
buf.WriteString(sb.offsetVar)
buf.WriteString(" + 1 AND ")
buf.WriteString(sb.limitVar)
buf.WriteString(" + ")
buf.WriteString(sb.offsetVar)
} else {
buf.WriteString("1 AND ")
buf.WriteString(sb.limitVar)
}
} else {
// As oraclePage is true, sb.offsetVar must not be empty.
buf.WriteString("r >= ")
buf.WriteString(sb.offsetVar)
buf.WriteString(" + 1")
}
buf.WriteLeadingString("FETCH NEXT ")
buf.WriteString(sb.limitVar)
buf.WriteString(" ROWS ONLY")
}
case Informix:
+4 -4
View File
@@ -261,10 +261,10 @@ func ExampleSelectBuilder_limit_offset() {
//
// Oracle
// #1: SELECT * FROM user
// #2: SELECT * FROM (SELECT ROWNUM r, * FROM (SELECT * FROM user) user) WHERE r >= :1 + 1
// #3: SELECT * FROM (SELECT ROWNUM r, * FROM (SELECT * FROM user) user) WHERE r BETWEEN :1 + 1 AND :2 + :3
// #4: SELECT * FROM (SELECT ROWNUM r, * FROM (SELECT * FROM user) user) WHERE r BETWEEN 1 AND :1
// #5: SELECT * FROM (SELECT ROWNUM r, * FROM (SELECT * FROM user ORDER BY id) user) WHERE r BETWEEN :1 + 1 AND :2 + :3
// #2: SELECT * FROM user OFFSET :1 ROWS
// #3: SELECT * FROM user OFFSET :1 ROWS FETCH NEXT :2 ROWS ONLY
// #4: SELECT * FROM user OFFSET 0 ROWS FETCH NEXT :1 ROWS ONLY
// #5: SELECT * FROM user ORDER BY id OFFSET :1 ROWS FETCH NEXT :2 ROWS ONLY
//
// Informix
// #1: SELECT * FROM user