Вычисление итогов

Добрый день.

В Dataset есть вычисляемое поле, но, к сожалению, я не могу в реестре вычислить итог по этому полю. Для выхода из ситуации я создал в таблице, выборке и датасете еще одно поле и попытался вставить в него вычесленное значение:

function ds_ContractOnDatasetCalcFields(Dataset) {
Dataset.Values('OVK') = Dataset.Values('Amount')/2........
Dataset('OVKNew') = Dataset.Values('OVK');
}

контекстное меню итогов у этого поля стало активным, в колонке отображаются нужные значения, но итоги (max, min, sum) равны нулю.

Может есть какой-нибудь способ подсчета итоговых значений по вычисляемым полям?

Спасибо.

Нравится

38 комментариев

В общем случае, чтобы рассчитать, например, сумму по вычисляемому полю нужно загрузить все записи датасета, вызвать для каждой OnDatasetCalcFields и т.д. Что, как Вы понимаете, будет очень медленно работать!

Поэтому ответ на Ваш вопрос

"Павел Крышкин" написал:Может есть какой-нибудь способ подсчета итоговых значений по вычисляемым полям?

:сделать это поле хранимым или вычисляемым во view.

:сделать это поле хранимым или вычисляемым во view.

Вы имеете ввиду
function grdDataOnCalcSummary(DataGrid, DataField, Value, SummaryType, DoCalcSummary)
?

Я так понимаю без исправления ошибки в ядре, из-за которой не работают итоги по калк-филдам, ничего не будет. Тот путь, по которому Вы пошли, он порочен :) Использовать поле в БД для хранения каких-то времнных данных, которые в общем случае у каждого клиента могут быть свои не совсем хорошо.
К тому же если работает строка

Dataset('OVKNew') = Dataset.Values('OVK');

то это, наверное, еще одна бага. Нельзя менять значение поля датасета без перевода его в состояние редактирования.

Я такое смог обойти только используя view

--
www.it-sfera.com.ua
Terrasoft Solution Partner

Если можно, поподробней.

Да, можно и вьюхой. Но не всегда :(
Или CustomSQLColumn. Добавляем в запрос такую колонку, в тексте которой и описываем формулу вычисления калкфилда. В датасете делаем обычное поле для этой колонки.

Не создавать вычисляемое поле в Датасете, а создать на стороне SQL новое представление ( VIEW ) где и проводить расчеты. Потом подключить в админке VIEW, как таблицу, а дальше - стандартно - SelectQuery.. Dataset.. Работаем :)

--
www.it-sfera.com.ua
Terrasoft Solution Partner

По CustomSQLColumn итоги в реестре не рассчитываться

--
www.it-sfera.com.ua
Terrasoft Solution Partner

"Виталий Ковалишин aka samael" написал:По CustomSQLColumn итоги в реестре не рассчитываться

Хм, не знал, спасибо.

"Underscore a.k.a. _" написал:Я так понимаю без исправления ошибки в ядре, из-за которой не работают итоги по калк-филдам, ничего не будет

Ну не то что бы это была ошибка :) Они не "не работают", итоги физически нельзя выбрать по Calc-полям.
В версии 3.3.1 появился метод OnDatasetCalcSummary, в котором можно реализовать собственный рассчет итогов. Эту функциональность мы специально реализовали для MemoryDataset. Но можно будет ее использовать и для Calc-полей. Для этого нам осталось дать возможность выбирать в гриде необходимость рассчета итогов по Calc полям - сейчас, как я уже говорил, она закрыта.

Ну да, итоги можно расчитать только для текущего пейджа:) И тогда будет слегка сбивать столку, если в одной колонке считаем для всех пейджей, а в другой только для текущего.

Почему только для текущего?

Ну допустим мы считаем калкполе A = 2*B, где B это поле БД. Стоя на первой странице грида мы будем иметь информацию для расчета значений поля A только для записей с первой страницы. Таким образом для калкполя мы можем посчитать итог только для текущей страницы.

Итог для calc-поля нужно посчитать отдельным запросом и все.

Про то что можно отедельным запросом понятно. Но придется создавать отдельный SQ для каждого такого поля. Как это сделать универсально (как сделано для обычных полей) я не представляю. А зная свойство человеческой натуры, можно сказать что разработчики будут ленится делать расчет итогов для каждого калкполя, которе они добавили в конфигурацию :)

В будущих версиях обязательно придумаем что нибудь более универсальное.

"Underscore a.k.a. _" написал:А зная свойство человеческой натуры, можно сказать что разработчики будут ленится

странно слышать такие слова :)

"Раловец Ольга" написал:странно слышать такие слова :)

Да ладно. Думаю каждый время от времени ленится. Просто для некоторых это становится нормой и они сами этого уже не замечают :)

Разработчик может не полениться, а следовать ТЗ, в котором явно не прописана необходимость вычисления итогов по хитрому полю))

ООО "Лайнсервис"
www.ls-crm.ru

Или же он может помнить про особенность этих полей, но решить, что раз в ТЗ не прописано... :)

"Underscore a.k.a. _" написал:Думаю каждый время от времени ленится

думаю, я знаю как минимум одного человека, который никогда не ленится :)

Надеюсь это Путин? :) Потому что писать таким образом о себе как минимум не скромно :)

что Вы, что Вы! как можно :) я говорю о своих коллегах

Подлизываться к начальству тоже к добродетелям не относится :)

Итоги не работают и по колонкам с под запросом.
Самое вменяемое решение - таки использовать отображение.
Хорошо б такой сервис создать.
А то

"Underscore a.k.a. _" написал:разработчики будут ленится

вначале создавать на стороне сервера, а потом сам сервис :)

Так вроде приняли идею про сервис. Осталось дождаться реализации.

Здравствуйте, Алексей!

"Ключник Алексей" написал:В версии 3.3.1 появился метод OnDatasetCalcSummary, в котором можно реализовать собственный рассчет итогов. Эту функциональность мы специально реализовали для MemoryDataset

Подскажите пожалуйста как это работает. Как подсчитать сумму в MemoryDataset и отобразить ее в итогах?

В обработчике события OnDatasetCalcSummary во второй аргумент SummaryValues можно заносить итоговое значение. Например, SummaryValues('Name')=555. В результате, в итоге для колонки Имя будет значение 555. При этом нужно присваивать DoCalc.Value = false, чтобы отключить стандартный подсчет итогов.
Относительно MemoryDataset: Вы можете создать его и наполнять значениями на событии OnDatasetAfterOpen. Наполнение реализовать согласно требуемой логики подсчета итогов. Но можно и напрямую заносить итоговое значение, без MemoryDataset, как я описал выше.

"Стоян Виталий" написал:В обработчике события OnDatasetCalcSummary во второй аргумент SummaryValues можно заносить итоговое значение. Например, SummaryValues('Name')=555. В результате, в итоге для колонки Имя будет значение 555. При этом нужно присваивать DoCalc.Value = false, чтобы отключить стандартный подсчет итогов.
Относительно MemoryDataset: Вы можете создать его и наполнять значениями на событии OnDatasetAfterOpen. Наполнение реализовать согласно требуемой логики подсчета итогов. Но можно и напрямую заносить итоговое значение, без MemoryDataset, как я описал выше.

Сделал, как Вы написали, но при нажатии правой кнопкой в строке итогов выходит исключение:
Объект TSObjectLibrary.MemoryDataset ({64250DFB-C6AA-4BC8-B4C6-515C52D98244}) не поддерживает интерфейс IDBDataset ({B77D78C1-40FD-4A5A-9592-DC0A6072AA3B})

Есть ли какой-нибудь способ подсчета значений поля в MemoryDataset минуя переход по записям, или может посоветуете какой нибудь другой компонент.
Задача следующая вывести общую сумму непосредственно после изменения значения колонки сумма в определенной строке, как в excel'e.

Вы можете использовать стандартные итоги по сумме, а обновлять значение по событию OnAfterPost, обращаясь к датасету реестра раздела, например таким способом: RefreshDataset(Self.Attributes('NotifyObject').ComponentsByName('dlData').Dataset)

"Стоян Виталий" написал:
Дело в том, что я пытаюсь реализовать все это на MemoryDataset'е, без окна редактирования, и вроди бы даже подсчет выполняется, но при изменении поля, для подсчета итогов приходится делать перебор всех записей и получается, указатель записи постоянно находися на последней записе. Можно ли как-то обрабатывать MemoryDataset не используя перемещение по его записям?

"Стоян Виталий" написал:Вы можете использовать стандартные итоги по сумме, а обновлять значение по событию OnAfterPost, обращаясь к датасету реестра раздела, например таким способом: RefreshDataset(Self.Attributes('NotifyObject').ComponentsByName('dlData').Dataset)

Спасибо Виталий!
Что-то я сразу не сообразил, что при редактировании непосредственно в Grid'е также срабатывает осбытие OnAfterPost.
Сделал на событиии OnAfterPost.

 Dataset.DisableEvents();
	var ID=Dataset.Values('ID');
	suma=0;
	Dataset.GotoFirst();
	for (var i = 0; i < Dataset.RecordsCount; i++) {
		suma=suma+Dataset.Values('Summa');
		Dataset.GotoNext();
	}	
	Dataset.Locate('ID',ID);
    Dataset.EnableEvents();
    LabelSum.Caption= suma;

Но только один вопросик на будущее: существует ли недокументированная возможность обращаться к MemoryDataset'у как к массиву значений? Ведь имхо он таковым и является.

Он-то конечно по структуре является, но реализует интерфейс IMemoryDataset, в котором не прописано обращение напрямую к определенной записи, как в массиве. Вот, например, перечень свойств интерфейса.
Можно считать вашу проблему решенной?

Спасибо, Виталий за помощь! Проблема решена.

Здравствуйте!
При работе с данным обработчиком OnDatasetCalcSummary возникает вопрос
Как различить вызываемые агрегатные функции при обработке события Dataset'a OnDatasetCalcSummary
Кстати говоря, пройдя по ссылке, можно найти решение, как различать различные поля Dataset'a по которым вызван итог.

Ответ на вопрос пользователя АльфаКрыса был предоставлен в теме по ссылке:

http://www.community.terrasoft.ua/forum/topic/8468

Дмитрий, спасибо за помощь. Пример своего кода с использованием Ваших рекомендаций можно посмотреть тут

Здравствуйте АК.

Если у Вас возникнут дополнительные вопросы - пожалуйста, обращайтесь. Всегда рады помочь ;)

Показать все комментарии