pagehelper-org/Mybatis-PageHelper · error · PageException

The column " " needs to define an alias

Error message

The column "${expression}" needs to define an alias

What it means

When PageHelper rewrites SQL Server queries it must duplicate ORDER BY expressions into the wrapping select's column list (via ROW_NUMBER). If an ORDER BY expression is not a simple column (e.g. a function like LOWER(name)) and does not appear in the original SELECT list, or appears as a complex expression without an alias, the parser cannot reference it safely and demands the query column define an alias.

Solutions

  1. Add an alias to the complex select expression and order by the alias: SELECT UPPER(name) AS upper_name FROM t ORDER BY upper_name
  2. Order by a plain column instead of an expression
  3. Include the ORDER BY expression as a plain column in the SELECT list with an alias
  4. Remove the expression from ORDER BY or move ordering into an outer wrapper query that you page over

Example fix

// before
SELECT UPPER(name) FROM users ORDER BY UPPER(name)

// after
SELECT UPPER(name) AS upper_name FROM users ORDER BY upper_name
Defensive patterns

Strategy: validation

Validate before calling

// Ensure every ORDER BY expression used in a paged SQL Server query is a plain column or aliased select item
for (String orderByExpr : extractOrderByExpressions(sql)) {
    if (orderByExpr.contains("(") && !selectListContainsAlias(sql, orderByExpr)) {
        throw new IllegalArgumentException("ORDER BY expression '" + orderByExpr + "' needs a select alias for pagination");
    }
}

Try / catch

try {
    return mapper.selectPaged(params);
} catch (PageException e) {
    if (e.getMessage().contains("needs to define an alias")) {
        log.warn("Aliasing required for paged ORDER BY, falling back to manual paging");
        return manualPagedSelect(params);
    }
    throw e;
}

Prevention

When it happens

Trigger: SQL Server pagination where an ORDER BY item is a non-Column expression (function, arithmetic) that is not a plain column in the select list, or the ORDER BY expression matches a select item that is a function/expression without an alias (e.g. SELECT UPPER(name) FROM t ORDER BY UPPER(name)).

Common situations: Ordering by a function or computed expression in SQL Server paged queries; ORM-generated SQL with expression-based ORDER BY; legacy SQL migrated to SQL Server pagination.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of pagehelper-org/Mybatis-PageHelper@c692616c5b (2026-09-08). Data as JSON: /api/errors/2cfe9727909b96ca. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/com/github/pagehelper/parser/defaults/DefaultSqlServerSqlParser.java:461

            if (selectExpressionItem != null) { // OrderByElement 在查询列表中
                Alias alias = selectExpressionItem.getAlias();
                if (alias != null) { // 查询列含有别名时用查询列别名
                    iterator.set(cloneOrderByElement(orderByElement, alias.getName()));

                } else { // 查询列不包含别名
                    if (expression instanceof Column) {
                        // 查询列为普通列,这时因为列在嵌套查询外时名称中不包含表名,故去除排序列的表名引用
                        // 例(仅为解释此处逻辑,不代表最终分页结果):
                        // SELECT TEST.A FROM TEST ORDER BY TEST.A
                        // -->
                        // SELECT A FROM (SELECT TEST.A FROM TEST) ORDER BY A
                        ((Column) expression).setTable(null);

                    } else {
                        // 查询列不为普通列时(例如函数列)不支持分页
                        // 此种情况比较难预测,简单的增加新列容易产生不可预料的结果
                        // 而为列增加别名是非常简单的,故此要求排序复杂列必须使用别名
                        throw new PageException("The column \"" + expression + "\" needs to define an alias");
                    }
                }

            } else { // OrderByElement 不在查询列表中,需要自动生成一个查询列
                if (expression instanceof Column) { // OrderByElement 为普通列
                    Table table = ((Column) expression).getTable();
                    if (table == null) { // 表名为空
                        if (allColumns ||
                                (allColumnsTables.size() == 1 && plainSelect.getJoins() == null) ||
                                aliases.contains(((Column) expression).getColumnName())) {
                            // 包含`*`查询列 或者 只有一个 `t.*`列且为单表查询 或者 其实排序列是一个别名
                            // 此时排序列其实已经包含在查询列表中了,不需做任何操作
                            continue;
                        }

                    } else { //表名不为空
                        String tableName = table.getName();
                        if (allColumns || allColumnsTables.contains(tableName)) {

View on GitHub (pinned to c692616c5b)