Как выполнить Oracle top-n (paged) запрос в SubSonic 2.2? - PullRequest
1 голос
/ 29 сентября 2010

( Отказ от ответственности: Я изменил / запутал некоторые имена переменных / таблиц / столбцов здесь по соображениям безопасности. Пожалуйста, простите меня, если что-то выглядит не так.)

Я создаю интерфейс для базы данных 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?

Ответы [ 3 ]

1 голос
/ 03 октября 2010

Похоже, ваш запрос не генерирует тот же SQL, что и текущий поставщик данных Oracle для 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 для подсказок о том, в чем может быть проблема.

1 голос
/ 04 февраля 2011

Я нахожусь в среде, использующей NET 2.0 и Oracle 9i R2, и я столкнулся с той же самой проблемой. Я использую SubSonic 2.2.

Я скачал исходники с GitHub, и вот что я нашел:

Код, цитируемый @ranomore (OracleDataProvider.GetSelectSql ()), вызывается только при использовании объекта SubSonic.Query. Так как OP и я используем объект Select, полученный из более нового и мощного объекта SubSonic.SqlQuery, OracleDataProvider.GetSelectSql () никогда не вызывается. Вместо этого OracleGenerator.BuildPagedSelectStatement () вызывается и генерирует SQL, который вы видите опубликованным OP. Этот код содержит ошибки, поскольку он никогда не добавляет предложения 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();
}

Выше работало для меня. Надеюсь, что это помогает другим!

0 голосов
/ 30 сентября 2010

Oracle будет в порядке с запросом Top-N, если внутренний SQL будет состоять из первого оператора (включая where и order by).

Итак, я бы сказал, что у Oracle нет особой причиныопустите их.

Никогда не использовал дозвуковой, не знаю, нужно ли вам делать это по-другому.

По производительности, индекс DISABLED_DATE, CREATED_DATE должен помочь (см .: http://blog.fatalmind.com/2010/07/30/analytic-top-n-queries/).

...