20.01.2004, 13:43 | #1 |
Участник
|
Вопрос: Существет ли какой-либо еще способ подсчитать количество строк в Query (несколько таблиц-источников), кроме тупого сканирования всех записей по while (qr.next)?
Дело в том, что это относительно медленный процесс. У меня получилось примерно 500 строк в секунду. Ответ:да, конечно, можно. SysQuery::countTotal(myQuery) |
|
20.01.2004, 14:43 | #2 |
Administrator
|
Проблема в том, что SysQuery::countTotal правильно работает только в случае, если в Query один DataSource.
Более правильный метод подсчета записей, возвращаемых Query см. в методе webTableLookup.run() Там есть вложенный метод computeRecordCount, который все и делает. Вкратце, суть метода такова. Сначала создается копия исходного Query. Для всех DataSource в Query отменяется динамическое создание списка выбираемых полей и добавляется только поле TableId (чтобы хоть что-то выбиралось). Далее, в самый главный DataSource добавляется Selection Field RecId с функцией агрегации COUNT (если по простому, делается SELECT COUNT(RecId)). Созданный Query запускается и получает результат. В большинстве случаев, результат верный. Однако, если в исходном используется GroupBy, функция вернет количество записей только в первой группе. Для исправления ситуации нужен небольшой bug fix. Во-первых, добавьте в функцию локальную переменную ret типа int. Во-вторых, вместо Код: return record.(recId); Код: ret = record.(RecId); while (queryRun.next()) { record = queryRun.getNo(1); ret += record.(RecId); } return ret;
__________________
Not registered yet? Register here! Have comments, questions, suggestions or anything else regarding our web site? Don't hesitate, send them to me |
|
20.01.2004, 15:12 | #3 |
Administrator
|
Вот SysQuery с методом countTotalRNR, который обобщает все вышесказанное (плюс еще немного к человеческому виду приведенный).
__________________
Not registered yet? Register here! Have comments, questions, suggestions or anything else regarding our web site? Don't hesitate, send them to me |
|
20.01.2004, 15:42 | #4 |
Участник
|
Цитата:
Код: ret = record.(RecId); while (queryRun.next()) { record = queryRun.getNo(1); ret += record.(RecId); } return ret; Моё предложение: Код: loops = 0; while (queryRun.next()) { record = queryRun.getNo(1); ret += record.(RecId); loops++; } ret = (loops ? loops : ret); return ret; |
|
20.01.2004, 19:44 | #5 |
Участник
|
чувствую, что вопрос еще открыт, поэтому рановато ему еще в FAQ .
переношу эту тему в обсуждение программирования. Спасибо, Wamr |
|
20.01.2004, 20:17 | #6 |
Участник
|
Итак, насколько я понимаю, есть метод countTotal - он возвращает количество записей в запросе. и есть countLoops - он возвращает количество группировок.
Насколько я понял Максима, countTotal дает направильные результаты когда в query прилинковано несколько таблиц. Так? |
|
20.01.2004, 20:35 | #7 |
Участник
|
например, в у меня стандартном демопримере
Код: static void Job10(Args _args) { QueryRun q = new QueryRun(querystr(LedgerTransAll)); ; info(strfmt('%1',SysQuery::countTotal(q))); } нормально работает и для запроса LedgerTrans, хотя там группировки. А вот для querystr(LedgerTable) показывает чушь, поскольку там dinalink. В этом проблема? Maxim, согласен, что код в webTableLookup.run() выглядит более правильным. Может сделаешь проект, в котором будет исправленный код для SysQuery с учетом замечаний wamr? Чтобы считался и loops тоже. Спасибо за качественный совет. И спасибо за webTableLookup.run() |
|
21.01.2004, 11:03 | #8 |
Участник
|
Можно несколько глупых вопросов? Я еще очень плохо ориентируюсь в Axapta вообще и где что искать в частности.
-) О какой версии идет речь? У меня 2.5 и класса webTableLookup я не нашел. Или где его искать? -) В примере исправленного кода SysQuery выложенного Максимом есть строка Код: countQuery = SysQuery::copyDynalinks(countQuery, _query); -) dinalink - это что собственно такое? Еще один совсем глупый вопрос: В коде Максима предельное значение счетчика вычисляется непосредственно в заголовке цикла Код: for (k = 2; k <= countQuery.dataSourceCount();k++) |
|
21.01.2004, 11:11 | #9 |
Участник
|
Господа модераторы, убейте, пожалуйста 2 из 3 повторяющих сообщений (loops++), а заодно и это.
К тему вернусь сегодня попозже. |
|
21.01.2004, 13:31 | #10 |
Участник
|
Цитата:
Сообщение от Владимир Максимов
-) О какой версии идет речь? У меня 2.5 и класса webTableLookup я не нашел. Или где его искать?
-) В примере исправленного кода SysQuery выложенного Максимом есть строка Код: countQuery = SysQuery::copyDynalinks(countQuery, _query); -) dinalink - это что собственно такое? Еще один совсем глупый вопрос: В коде Максима предельное значение счетчика вычисляется непосредственно в заголовке цикла Код: for (k = 2; k <= countQuery.dataSourceCount();k++) В 2.5 действительно нет класса webTableLookup. Поскольку корпоративный портал для 3.0 сильно доработали. SysQuery::copyDynalinks также присутствует только в 3.0. Этот метод копирует связи (relation) между таблицами. Причем связи, установленные Аксаптой автоматически. См. руководство разработчика, ключевые слова "auto-define relations", "table relations", "Creating a relationship on an Extended Data Type". Это есть и в 2.5, и в 3.0. Руководство разработчика для 3.0 можно взять и здесь http://technet.navision.com/usered/Axapta3...v02.00-ENUS.zip Насчет вычислений. Нигде не видел описания поведения в таких случаях специально для Аксапты. Подозреваю, что и в этом случае будут действовать правила из Java - будет вычисляться. Эксперимент показывает, что вычисляется каждый раз. |
|
21.01.2004, 14:57 | #11 |
Участник
|
Большое спасибо.
Однако вопрос по DynaLink нуждается в уточненнии. В коде Максима (исправление SysQuery) создание копии Query осуществляется следующим образом: Код: public client server static Integer countTotalRNR(Query _query) { Query countQuery = _query.newObject(_query.pack(FALSE)); // Add contribution from dynalinks... countQuery = SysQuery::copyDynalinks(countQuery, _query); } Код: Query countQuery = _query.newObject(_query.pack(TRUE)); Если тем не менее это необходимо, то есть ли в этом необходимость в версии 2.5? Если есть, то как это сделать вручную (поскольку нет метода SysQuery::copyDynalinks() ) Извиняюсь за такую навязчивость, но при такой слабой документированности Axapta я по пол-дня соображаю что же именно и каким образом делает та или иная команда |
|
21.01.2004, 15:24 | #12 |
Участник
|
при программном создании query связи автоматически не создаются.
в отчетах и формах надо указать галочку, что автоматически создавать связи можно, тогда для отчетов и форм, Аксапта создаст связь автоматом. Если объекты создаются из AOT, то там эту галочку разработчик должен указать в свойствах. Почему dinalink копируется, а не пересоздается? Потому что в исходном запросе динасвязи могли быть подредактированы программистом. |
|
21.01.2004, 15:34 | #13 |
Участник
|
В данном случае речь идет не о создании query с нуля, а о создании query как копии существующего. Для чего и используется _query.pack().
Но ведь, если я правильно понимаю, _query.pack(TRUE) как раз и должен передать все настройки сделанные в query. В том числе и изменения внесенные в связи как самой Axapta, так и пользователем. Или это не так? |
|
21.01.2004, 15:45 | #14 |
Участник
|
pack нужен не для того, чтобы скопировать все, а для того, чтобы передать информацию с клиента на сервер и обратно.
см. http://technet.navision.com/usered/BPH/Bes.../PackUnpack.htm Что конкретно делает pack зависит от реализации класса. Поэтому надо проверить, передаются ли dinalink в pack'е. Я наверняка не знаю. |
|
21.01.2004, 17:43 | #15 |
Участник
|
В виде исключения, описание Query.Pack() есть в АОТ. Оказывается он просто не пакует DynaLinks, а параметр всего лишь влияет на то выдавать сообщение об ошибке в случае наличия DynaLinks или нет.
В 2.5 если необходимо паковать DynaLinks советуют их явно прописывать в DataSource Т.е. изменения Максима для 2.5 получается неприменимы? Или возможны варианты? |
|
21.01.2004, 17:51 | #16 |
Участник
|
надо Максима дождаться. Он сейчас не в офисе.
|
|
21.01.2004, 18:52 | #17 |
Участник
|
Хочу исправить свою ошибку:
Код: loops = 0; while (queryRun.next()) { record = queryRun.getNo(1); ret += record.(RecId); loops++; } ret = (loops>1 ? loops : ret); return ret; С задачей подсчета строк в запросе я сталкивался в 2х случаях: - когда требовалось выводить какие-то агрегированные значения в форме с учетом фильтров пользователя и dynalink-ов c другими формами; - для инициализация прогресса перед выполнением какого-то длительного процесса. И в том, и в другом случаи важен не только результат, но и скорость. Т.е. простой перебор строк (читай countTotal) не подходит. При наличии GROUP BY даже метод Максима приходит к перебору. Простого способа посчитать строки с группировками НЕТ. Т.е. для таких вычислений надо искать какой-то обходной путь. Если честно, то я почти никогда не использовал универсальный метод подсчета кол-ва строк в запросе, так как всегда старался сделать несколько вычислений (кол-ва, суммы..) за один проход ----------------------- Паковать dynalink. Не представляю себе, как можно корректно упаковать динамическую связь одного объекта (курсора) с другим объектом (запрос)? А как потом распаковать? |
|
21.01.2004, 19:36 | #18 |
Участник
|
Цитата:
Сообщение от Wamr
Уточню, что под количество строк запроса я понимаю кол-во строк получаемых в результате запроса после всех фильтраций и агрегаций.
countLoops и должен возвращать число группировок, а countTotal должен возвращать БЫСТРО число строк в таблице. |
|
21.01.2004, 20:07 | #19 |
Участник
|
Цитата:
Сообщение от mazzy
countLoops и должен возвращать число группировок,
в стандартном countPrim. |
|
21.01.2004, 20:39 | #20 |
Участник
|
ооо. ну ни фига себе тема...
не, метод Максима тоже не пойдет, поскольку выборка делается там, где ее вызвали. Если вызвали на клиенте, то и запрос выполняться будет на клиенте... А это трафик по тонкому каналу... |
|