2010-09-29 97 views
1

免责声明:我改变/混淆一些变量/表/列名在这里出于安全原因的,如果事情看起来有点过,请原谅我。)如何在SubSonic 2.2中执行Oracle top-n(分页)查询?

我建立一个前端一个Oracle 10g数据库,我试图获取分页数据。除了分页,下面的亚音速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中执行此操作?

回答

1

看起来您的查询不会生成与当前Oracle Data Provider for SubSonic相同的SQL。这里是相关的代码(从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进行比较,以了解可能存在问题的提示。

-1

如果内部SQL将由第一条语句(包括where和order by)组成,那么对于Top-N查询,Oracle会很好。

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

从未使用亚音速,不知道你是否需要做不同。

表现明智,DISABLED_DATE,CREATED_DATE上的索引应该做的伎俩(见:http://blog.fatalmind.com/2010/07/30/analytic-top-n-queries/)。

1

我在使用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子句添加到它最终生成的分页查询中。

我换成BuildPagedSelectStatement()的东西的基础上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(); 
} 

。希望这可以帮助别人!