(免责声明: 出于安全原因,我在此处更改/混淆了一些变量/表/列名称。如果看起来有些不对劲,请原谅我。)

我正在构建 Oracle 10g 数据库的前端,并且正在尝试获取分页数据。除了寻呼之外,以下 SubSonic 2.2 代码按照我想要的顺序提供了我想要的内容:

var q = new Select()
  .From(AppDb.MyTable.Schema)
  .Where(AppDb.MyTable.DisabledDateColumn).IsNull()
  .OrderDesc(AppDb.MyTable.CreatedDateColumn.ColumnName)

System.Console.Out.Writeline(q.BuildStatement());

这会产生以下 SQL:

SELECT
    MYSCHEMA.MYTABLE.ID,
    MYSCHEMA.MYTABLE.DISABLED_DATE
FROM
    MYSCHEMA.MYTABLE
WHERE
    MYSCHEMA.MYTABLE.DISABLED_DATE IS NULL
ORDER BY
    CREATED_DATE DESC

然后我尝试引入分页:

var q = new Select()
  .From(AppDb.MyTable.Schema)
  .Where(AppDb.MyTable.DisabledDateColumn).IsNull()
  .OrderDesc(AppDb.MyTable.CreatedDateColumn.ColumnName)
  .Paged(0, 10);

它消除了我的 WHERE 和 ORDER BY 子句:

SELECT * FROM (
    SELECT
        MYSCHEMA.MYTABLE.ID,
        MYSCHEMA.MYTABLE.DISABLED_DATE,
        ROWNUM as row_number
    FROM
        MYSCHEMA.MYTABLE
)
WHERE
    row_number BETWEEN 1 AND 10

我是 SubSonic 的新手,所以我不知道这是否是一个错误,或者我只是没有以首选方式执行此操作,或者 Oracle 是否要求以不同的、更以 Oracle 为中心的方式完成此操作。(甲骨文似乎要求一切都如此。)

我想要的是(以防不明显)每个后续页面都包含 10 个下一个最近创建的非禁用记录。我怎样才能在 SubSonic 2.2 中做到这一点?

有帮助吗?

解决方案

看起来您的查询没有生成与当前相同的 SQL 适用于 SubSonic 的 Oracle 数据提供程序 应该。下面是相关代码(从第 852 行开始):

    if(qry.PageIndex < 0)
        query = String.Format("{0} {1} FROM {2}.{3} {4} {5}",select ,columns, table.SchemaName, table.Name, where, order);
    else
    {
        int start = qry.PageIndex * qry.PageSize;
        int end = (qry.PageIndex + 1) * qry.PageSize;

        const string cteFormat =
                    "WITH pagedtable AS (SELECT {0}, ROW_NUMBER () OVER ({1}) AS rowindex FROM {2}.{3} {4}) SELECT {5}, rowindex FROM pagedtable WHERE rowindex >= {6} AND rowindex < {7} ORDER BY rowindex";
        query = string.Format(cteFormat, columns, order,table.SchemaName, table.Name, where, columns.Replace(table.Name + ".", String.Empty), start, end);
    }
    return query;

也许更新当前源可以解决这个问题。如果实际提供程序出现问题,您可以将其与 SqlDataProvider 进行比较,以获取可能存在问题的提示。

其他提示

我在使用.NET 2.0和Oracle 9i R2的环境和我遇到同样的确切的问题。我使用亚音速2.2。

我下载从GitHub源,这是我的发现:

通过@ranomore引用的代码(OracleDataProvider.GetSelectSql())仅使用SubSonic.Query对象时调用。由于OP和我使用的是从较新的,更强大的SubSonic.SqlQuery对象得出的选择对象,OracleDataProvider.GetSelectSql()不会被调用。相反, OracleGenerator.BuildPagedSelectStatement()被调用,并生成你看到张贴的OP的SQL。此代码是越野车,因为它从来没有添加WHERE和ORDER BY子句将其最终产生的分页查询。

我基于ANSISqlGenerator.BuildSelectStatement()的东西替换BuildPagedSelectStatement()的内容

public override string BuildPagedSelectStatement()
{
    int startnum = query.PageSize * query.CurrentPage + 1;
    int endnum = query.PageSize * query.CurrentPage + query.PageSize;
    string orderBy = String.Empty;

    if (this.query.OrderBys.Count > 0)
        orderBy = GenerateOrderBy();

    //The ROW_NUMBER() function in Oracle requires an ORDER BY clause.
    //In case one is not specified, we need to halt and inform the caller.
    if(orderBy.Equals(String.Empty))
        throw new ArgumentException("There is no column specified for the ORDER BY clause", "OrderBys");

    System.Text.StringBuilder sql = new System.Text.StringBuilder();

    //Build the command string
    sql.Append("WITH pagedtable AS (");
    sql.Append(GenerateCommandLine());

    //Since this class is for Oracle-specific SQL, we can add a hint
    //which should help pagination queries return rows more quickly.
    //AFAIK, this is only valid for Oracle 9i or newer.
    sql.Replace("SELECT", "SELECT /*+ first_rows('" + query.PageSize + "') */");

    sql.Append(", ROW_NUMBER () OVER (");
    sql.Append(orderBy);
    sql.Append(") AS rowindex ");
    sql.Append(Environment.NewLine);
    sql.Append(GenerateFromList());
    sql.Append(GenerateJoins());

    sql.Append(GenerateWhere());

    if (query.Aggregates.Count > 0)
    {
        sql.Append(GenerateGroupBy());
        sql.Append(Environment.NewLine);
        sql.Append(GenerateHaving());
    }

    sql.Append(") SELECT * FROM pagedtable WHERE rowindex >= ");
    sql.Append(startnum);
    sql.Append(" AND rowindex < ");
    sql.Append(endnum);
    sql.Append(" ORDER BY rowindex");

    return sql.ToString();
}

以上为我工作。希望这可以帮助别人!

如果内部 SQL 由第一个语句(包括 where 和 order by)组成,Oracle 就可以使用 Top-N 查询。

所以,我想说 Oracle 没有特定的理由来忽略它们。

从未使用过亚音速,不知道是否需要在那里做不同的事情。

从性能角度来看,DISABLED_DATE、CREATED_DATE 上的索引应该可以解决问题(请参阅: http://blog.fatalmind.com/2010/07/30/analytic-top-n-queries/).

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top