Как можно сделать запрос Oracle Top-N (Chasted) в дозвуковой 2.2?
-
26-09-2019 - |
Вопрос
(Отказ от ответственности: Я поменял / запустил некоторые из имени переменных / таблиц / столбцов здесь по соображениям безопасности. Пожалуйста, прости меня, если что-то выглядит немного.)
Я строю вторжение в базу данных 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);
И он вытирает мой, где и порядок по пунктам:
SELECT * FROM (
SELECT
MYSCHEMA.MYTABLE.ID,
MYSCHEMA.MYTABLE.DISABLED_DATE,
ROWNUM as row_number
FROM
MYSCHEMA.MYTABLE
)
WHERE
row_number BETWEEN 1 AND 10
Я совершенно новой для дозвуковой, поэтому я не знаю, если это ошибка, или я просто не делаю это предпочтительным образом, или если Oracle требует, чтобы это было сделано в другом, более ориентированном на оракул. (Oracle, кажется, требует всего во всем.)
Что я хочу, на случай, если это не очевидно, каждая преуспевающая страница включает 10 следующих последних, созданных неразъемных записей. Как я могу сделать это в дозвуковой 2.2?
Решение
Похоже, ваш запрос не генерирует тот же SQL, что и текущий 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 (oracledatataProvider.getselectsql ()), называется только при использовании объекта Subsonic.Query. Поскольку OP и я используют объект SELECT, который получен из более нового и более мощного объекта Subsonic.sqlquery, oracledataProvider.getselectsql () никогда не вызывается. Вместо, OracleGenerator.BuildPagedSelectedStement () Вызывается и генерирует SQL, вы видите, опубликованные ОП. Этот код BUGGY, так как он никогда не добавляет, где и порядок по пунктам Pagination его в конечном итоге генерирует.
Я заменил содержимое BuildPagedSelectementStement () с чем-то на основе ANSISQLGENERATOR.BUILDSELECTSTSTEMENT ():
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();
}
Выше сработало для меня. Надеюсь, это поможет другим!
Oracle будет в порядке с помощью Top-n Query, если внутренний SQL будет состоять из первого утверждения (в том числе и порядка).
Итак, я бы сказал, что нет особой причины оракула, чтобы их опустить.
Никогда не использовал подгруппу, не знаю, если вам нужно сделать это отличаться там.
Performance Wise, индекс на disadov_date, create_date должен сделать трюк (см.: http://blog.fatalmind.com/2010/07/30/analytic-top-n-queries/).