如何在 SubSonic 2.2 中执行 Oracle top-n(分页)查询?

发布于 2024-09-25 10:10:29 字数 1324 浏览 0 评论 0原文

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

我正在构建一个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 为中心的方式完成此操作。 (Oracle 似乎要求所有内容都如此。)

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

(Disclaimer: I changed/obfuscated some of the variable/table/column names here for security reasons. Please forgive me if something looks a little off.)

I am building a front-end to an Oracle 10g database, and I'm trying to get paged data. Aside from paging, the following SubSonic 2.2 code gives me what I want, in the order I want it:

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

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

This yields the following SQL:

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

Then I try to introduce paging:

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

And it wipes out my WHERE and ORDER BY clauses:

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

I'm brand new to SubSonic, so I don't know if that's a bug, or I'm just not doing it the preferred way, or if Oracle demands that this be done in a different, more Oracle-centric way. (Oracle seems to demand that of everything.)

What I want, in case it isn't obvious, is each succeeding page to include the 10 next most-recently-created, non-disabled records. How can I do this in SubSonic 2.2?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

未蓝澄海的烟 2024-10-02 10:10:29

看起来您的查询没有生成与当前 Oracle Data Provider for SubSonic 应该。以下是相关代码(从第 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 进行比较,以获取可能存在问题的提示。

It looks like your query is not generating the same SQL as the current Oracle Data Provider for SubSonic should. Here is the relevant code (starting at line 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;

Perhaps an update to current source would do the trick. If there is something wrong with the actual provider, you can compare it to the SqlDataProvider for hints as to what might be the problem.

别在捏我脸啦 2024-10-02 10:10:29

我在使用 NET 2.0 和 Oracle 9i R2 的环境中,遇到了同样的问题。我正在使用 SubSonic 2.2。

我从 GitHub 下载了源代码,这就是我发现的:

@ranomore (OracleDataProvider.GetSelectSql()) 引用的代码仅在使用 SubSonic.Query 对象时才会被调用。由于 OP 和我自己使用从更新且更强大的 SubSonic.SqlQuery 对象派生的 Select 对象,因此 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();
}

上面的内容对我有用。希望这对其他人有帮助!

I'm in an environment using NET 2.0 and Oracle 9i R2 and I ran into the same exact problem. I'm using SubSonic 2.2.

I downloaded the source from GitHub and this is what I found:

The code quoted by @ranomore (OracleDataProvider.GetSelectSql()) is only called when using the SubSonic.Query object. Since the OP and myself use the Select object which is derived from the newer and more powerful SubSonic.SqlQuery object, OracleDataProvider.GetSelectSql() never gets called. Instead, OracleGenerator.BuildPagedSelectStatement() gets called and generates the SQL you see posted by the OP. This code is buggy as it never adds the WHERE and ORDER BY clauses to the pagination query it ultimately generates.

I replaced the contents of BuildPagedSelectStatement() with something based on ANSISqlGenerator.BuildSelectStatement():

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();
}

The above worked for me. Hope this helps others!

烟─花易冷 2024-10-02 10:10:29

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

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

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

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

Oracle would be fine with the Top-N query if the inner SQL would consist of the first statement (including where and order by).

So, i'd say there is no Oracle specific reason to omit them.

Never used subsonic, don't know if you need to do it different there.

Performance wise, an index on DISABLED_DATE, CREATED_DATE should do the trick (see: http://blog.fatalmind.com/2010/07/30/analytic-top-n-queries/).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文