Итоговые суммы полей
Модератор: kdv
Итоговые суммы полей
Понятно, что добыть сумму числового поля несложно, для того есть грегатная функция Sum(Chisl_Pole).
Но как это сделать наименее трудоемко в следующем случае:
Есть мастер-деталь связка. В деталь-таблице 8 полей дабл-пресижн. При переходе по мастер-таблице значения естественно меняются согласно записям. Вот как покрасивше все это сделать? Сделать еще одну деталь- таблицу с итогами для того же ID? И апдейтить ее только от случая к случаю, при изменении чисел в этих восьми полях? Или запрашивать восемь сумм всякий раз при скроллировании мастер-таблицы?
Может быть, существуют еще какие варианты, более мудрые?
Для справки: FB 1.5.2, D6, использую компоненты IBObjects, но разницы, думаю, нет... Квайери - он и в Африке квайери. Полученные суммы я хочу выводить в панелях статус-строки, ну да это не есть важно.
Но как это сделать наименее трудоемко в следующем случае:
Есть мастер-деталь связка. В деталь-таблице 8 полей дабл-пресижн. При переходе по мастер-таблице значения естественно меняются согласно записям. Вот как покрасивше все это сделать? Сделать еще одну деталь- таблицу с итогами для того же ID? И апдейтить ее только от случая к случаю, при изменении чисел в этих восьми полях? Или запрашивать восемь сумм всякий раз при скроллировании мастер-таблицы?
Может быть, существуют еще какие варианты, более мудрые?
Для справки: FB 1.5.2, D6, использую компоненты IBObjects, но разницы, думаю, нет... Квайери - он и в Африке квайери. Полученные суммы я хочу выводить в панелях статус-строки, ну да это не есть важно.
-
- Заслуженный разработчик
- Сообщения: 644
- Зарегистрирован: 15 фев 2005, 11:34
Спасибо за быстрый ответ, кажется, я не корректно задал вопрос:Ivan_Pisarevsky писал(а):Вполне достаточно добавить поле, а не таблицу, хранить эту сумму и пересчитывать триггером при изменениии слагаемых.Сделать еще одну деталь- таблицу с итогами для того же ID?
Хотя, если не тормозит динамический подчет, то с ним хлопот меньше.
Я имел в виду не сумму полей, а суммы по столбцам, т.е. не Стоимость+НДС, а итог Стоимостей и Итог НДС-ов (ну, как бывает внизу каждого столбца).
Если я правильно понял, то Вам в мастер таблице необходимо видеть суммы по столбцам деталь таблицы. Я бы такую задачу решал используя агрегат Sum с группировкой Group by. Это в таких случаях традиционное и тривиальное решениеsolo писал(а):Спасибо за быстрый ответ, кажется, я не корректно задал вопрос:Ivan_Pisarevsky писал(а):Вполне достаточно добавить поле, а не таблицу, хранить эту сумму и пересчитывать триггером при изменениии слагаемых.Сделать еще одну деталь- таблицу с итогами для того же ID?
Хотя, если не тормозит динамический подчет, то с ним хлопот меньше.
Я имел в виду не сумму полей, а суммы по столбцам, т.е. не Стоимость+НДС, а итог Стоимостей и Итог НДС-ов (ну, как бывает внизу каждого столбца).
Спасибо большое! Кое-что проясняется. Но дело в том, что деталь у меня для каждого мастера тоже не вся показывается. Там достаточно наворочено: мастер таблица - деревянная : улицы, в них - дома, в них - квартиры. Вот и деталь-Query тоже не Selest * from DetalTable, а еще и по условию where дата начисления в периоде между началом и концом месяца. Вот хожу я по мастеру - меняется деталь только за январь. Выбираю февраль - и у этого мастера показываются только февральские начисления. Выбираю полгода - начисления с января по июнь, год - начисления за весь год. Такая байда. Ну, может знаете, месяц меняется компонентом TVolgaPeriod...kdv писал(а):а я бы не морочил голову с агрегатами, и сделал бы для мастера столбец, который вычисляет сумму триггерами.
В дальнейшем, при увеличении объема данных, это сэкономит время.
Вооот... И при всех вот этих издевательствах: как при смене мастера, так и при смене периода (прямо на форме с деталь-таблицей стоит этот TVolgaPeriod, щелкаешь по нему, он и меняет: Январь 2005, Февраль 2005...) - надо всякий раз иметь сумму под каждым из 8 столбцов.
Если ее кажный раз перезапрашивать дополнительным Квайери - не будет ли тормозов при сроллинге мастер-таблицы? Да, кстати, напоминаю, что она деревянная, и начисления могут быть только у квартир или у домов, у которых нет внутренних квартир. Ну, допустим, захожу я в узел "улица Ленина" - разворачивается куча домов. Тут и запрос с суммами не грех обновить - все равно дома не моментально разворачиваются. Захожу в 1 из домов - там 100 квартир. Тоже обновляю запрос сумм начислений. А потом-то я просто хожу по квартирам курсором... Что, на каждый скролл - обновлять SummQuery?
Вы, наверное, меня уже ненавидите ?
Вот и получается, что хранение суммы в мастер таблице не спасает. Вообще здесь советами не обойтись, посиди подумай, как правильно организовать БД и запросы. Мы в таких случаях, как правило пишем ХП, которая выдает нам детальный набор. В этой ХП прописываем все условия отбора. Мастер набор мы получаем запросом к ХП с агрегированием и группировкой. Все не так уж сложно.
Попробую. Если что выгорит - рапортую.SAMZ писал(а):Вот и получается, что хранение суммы в мастер таблице не спасает. Вообще здесь советами не обойтись, посиди подумай... Все не так уж сложно.
А пока еще один вопрос:
Не совсем понимаю Suspend. Нет, что это примерно, я понимаю. Что она останавливает обработку и ожидает дальнейших действий.
Вот и вопрос на эту тему:
Жму на кнопку "Начислить". Запускается ХП Sp_Nachisl
Код: Выделить всё
BEGIN
...
FOR SELECT Кучу полей FROM TB_Services
into :Кучу переменных
Where там, где куча условий
do begin
Тут - самое главное: верстаются начисления денег, льготы,
субсидии, короче, вся та ересь на 8 полей, про которые я говорил.
Всякие цены и жилплощади берутся из таблицы TB_Services.
Довольно быстро и красиво, лучше, чем в 1С :-)
end
...
Suspend
...
END
А если электроэнергия?
Как мне в этом цикле остановится перед начислением электроэнергии и пнуть клиента, чтобы он показал окошко типа "Введите показания счетчика за месяц"? А потом забрал эти показания и продолжил расчет?
Предполагаю, что как-то с Suspendom надо крутиться, но как точно - еще не понимаю.
(Теперь точно побьют
Если модераторы увидят этот твой вопрос, то не побьют, а начнут морально убивать, и, вероятно будут правы.solo писал(а):SAMZ писал(а): Не совсем понимаю Suspend. Нет, что это примерно, я понимаю. Что она останавливает обработку и ожидает дальнейших действий.
Вот и вопрос на эту тему:(Теперь точно побьют :roll:
Такое впечатление, что у тебя какая-то каша в голове.
Suspend- это очень просто. Сформировал строку данных-результатов, хочешь передать ее в DataSet ставь Suspend. У тебя, как мне кажется, Suspend стоит вне цикла и, следовательно ты ничего, кроме последней строки не увидишь.
Далее, по-поводу твоего вопроса о электроэнергии. Это же совсем другая песня. Здесь не просто запрос, а некоторая проверка достаточности данных для проведения определенного расчета с определенным клинтом. Тебе нужно подумать, как организовать этот бизнес процесс, что проверять перед расчетом, о чем предупредить, что возложить на сервер, что на клиентскую часть, и.т.д.
-
- Заслуженный разработчик
- Сообщения: 644
- Зарегистрирован: 15 фев 2005, 11:34
А еще бывают льготы, субсидии, переплапнировки квартир с изменением площадей (типа, то считать балкон жилплощадью, то не считать) и тп. т.е. все твой слагаемые должны иметь период действияТак вот: если это - отопление, вода или сортир - то жилплощадь известна заранее (Result = :Жилплощадь*Тариф), если сортир или вода - Кол-во проживающих*Тариф.
Ничего не останавливается, данныя строка выплевывается клиенту, а ХП работает дальше.Не совсем понимаю Suspend. Нет, что это примерно, я понимаю. Что она останавливает обработку и ожидает дальнейших действий.
Побойтесь Билла Гейтса!Ivan_Pisarevsky писал(а):А еще бывают льготы, субсидии, переплапнировки квартир с изменением площадей (типа, то считать балкон жилплощадью, то не считать) и тп. т.е. все твой слагаемые должны иметь период действия
Да ни в коем разе! Заранее оговорил, что никакой периодики! Плюс полная возможность менять вручную любые значения, достаточно поставить галку "считать вручную". После полугодовых сношений с очередным навороченным чудом 1С (дело рук крутой фирмы Эффект-Информ) клиент отчаянно пытается вернуть конфигурацию разработчику. А основным его требованием ко мне является "чтобы без всякой глупой периодики, блокирования удалений и чтобы было все прозрачно и как можно проще и нагляднее"
Уфф, напомнили 1С... Сразу настроение испортилось... Я же вообще-то не программист, а сисадмин. А сисадмину нельзя напоминать про бухов и 1С.
Наверное, из моих вопросов понятно, что я не гигантский шедевр ваяю. Цель - больше в освоении технологии. Ну, и может быть простят неуплату коммунальных за год Илит хотя бы спишут часть.
О чем это я? Ах да!
Так как мне остановить цикл и спросить-то на клиенте "Введите значение счетчика"?
Мне кажется, что здесь нет универсальных решений. Никаких циклов останавливать не надо. Тебе для себя надо решить, чего ты хочешь. Как можно понять из твоих писем, ты организуешь расчет по каким-то клинтам. Если для кокого-то клиента не хватает данных для корректного расчета (например, показаний счетчика) ну выведи в результатах по этому клиенту для этого расчета информацию (признак), предупреждающий о наступлении такого неприятного события. По этому признаку у клиента организуй предупреждение и интерфейс ввода доп.информациеи с пересчетом. Все это только умозрительный вариант. Можно делать так, можно иначе. Можно генерировать события, можно работать с исключениями. Можно все возложить на клиента, можно все это как-то распределить между клиентом и сервером. Но принять решение о том, КАК это сделать - это твоя проблема. Никто за тебя это не решит.А основным его требованием ко мне является "чтобы без всякой глупой периодики, блокирования удалений и чтобы было все прозрачно и как можно проще и нагляднее"
Уфф, напомнили 1С... Сразу настроение испортилось... Я же вообще-то не программист, а сисадмин. А сисадмину нельзя напоминать про бухов и 1С.
О чем это я? Ах да!
Так как мне остановить цикл и спросить-то на клиенте "Введите значение счетчика"?
-
- Заслуженный разработчик
- Сообщения: 644
- Зарегистрирован: 15 фев 2005, 11:34
На мой взгляд тут можно обойтись всего несколькими таблицами:Да ни в коем разе! Заранее оговорил, что никакой периодики! Плюс полная возможность менять вручную любые значения, достаточно поставить галку "считать вручную". После полугодовых сношений с очередным навороченным чудом 1С (дело рук крутой фирмы Эффект-Информ) клиент отчаянно пытается вернуть конфигурацию разработчику. А основным его требованием ко мне является "чтобы без всякой глупой периодики, блокирования удалений и чтобы было все прозрачно и как можно проще и нагляднее"
1. клиенты(храним карточку клиента со всеми реквизитами)
2. платежи (идклиента, месяц, сумма, из_каких_начислений_собрана сумма)
3. начисления(тип, коэфициет, сумма, период действия) /*для всех клиентов*/
4. начисления_по_клиенту(тип, коэфициет, сумма, период действия, идклиента) /*здесь всякие льготы, субсидии, кол-во народу, площади*/
Перед распечаткой листочков все остальное вычисляешь, берешь клиента начисляешь ему основные платежи, потом всякие льготы.
Хотя болтовня это все, спроектировать БД можно только имея на руках всю информацию, входные-выходные данные
Здравствуйте, как это не надо? Или я по ошибке FOR SELECT циклом называю? Тогда пардон. Ну все равно же это что-то типа перебора, да?SAMZ писал(а):Мне кажется, что здесь нет универсальных решений. Никаких циклов останавливать не надо.
Р-р-р-р!!! Товарищи дорогие! Да понимаю я постановку задачи. При наступлении в цикле (ну пусть не в цикле, а в FOR SELECT) события, при котором попадается услуга, требующая значения, на клиента надо отправить сигнал, чтобы он показал форму ввода этого значения. А потом забрать и продолжить расчет в этой же процедуре.SAMZ писал(а):Тебе для себя надо решить, чего ты хочешь. Как можно понять из твоих писем, ты организуешь расчет по каким-то клинтам. Если для кокого-то клиента не хватает данных для корректного расчета (например, показаний счетчика) ну выведи в результатах по этому клиенту для этого расчета информацию (признак), предупреждающий о наступлении такого неприятного события. По этому признаку у клиента организуй предупреждение и интерфейс ввода доп.информациеи с пересчетом.
Ну как еще проще сказать! Отопление значения не требует, т.к. площадь жилья не меняется раз в месяц., вода или канализация - тоже не требует, т.к. количество задниц - постоянная характеристика клиента (Условно). А вот электроэнергия - от случая к случаю.
Мне не нужна постановка задачи, не блок-схема, это я понимаю. А вот живой кусок кода из процедуры не помешал бы.
Вот код процедуры расчета:
Код: Выделить всё
begin
/* № 0 */
execute procedure pr_add_n_family THMN_MID, D_BEG, D_FIN returning_values :opchelnum ; /*Получаем количество задниц за этот месяц*/
/* № 1 Delete if exists */
IF (EXISTS(SELECT MID, D_BEGIN, D_END FROM NACHISL
WHERE (MID = :THMN_MID AND D_BEGIN = :D_BEG AND D_END = :D_FIN ))) THEN
DELETE FROM NACHISL WHERE (MID = :THMN_MID AND D_BEGIN = :D_BEG AND D_END = :D_FIN ); /*Удаляем ранее посчитаные, если есть*/
/* № 3 Square & OSquare*/
SELECT THEMAIN.SQUARE, THEMAIN.OSQUARE FROM THEMAIN
WHERE THEMAIN.MID = :THMN_MID
INTO :opSQUARE, :opOSQUARE; /*Забираем площадь общую и отапливаемую из таблицы клиентов*/
/* № 4 Nachislenie*/
FOR SELECT MID, SRV_NAME, S_PRICE, NOT_SRVS, SPOS_NUM, TI_NAME /*[b]Вот про этот цикл я и говорил[/b]*/
FROM SERVICES /* эта таблица держит услуги по каждому клиенту, их тарифы, способы расчета, типы услуги, короче - у кого что есть */
WHERE (MID = :THMN_MID)
INTO :opMID, :opSRV_NAME, :opN_PRICE, :opNOT_SRVS, :opSPOS_NUM, :OPTI_NAME
DO
BEGIN
IF (:OPNOT_SRVS != 'Y' ) THEN
BEGIN /*ЕСЛИ НЕ СТОИТ ЧЕКА STOP*/
/*Вычисляем по тарифу и загоняем в переменную oppo_tarifu*/
execute procedure [b]pr_choos_sposob[/b] opspos_num, opchelnum, opn_price, opsquare, oposquare returning_values :oppo_tarifu;
/* Get next ID */
opNewID = GEN_ID(SCH_NACH, 1);
INSERT INTO NACHISL(
NID,
MID,
D_BEGIN, /*Дата начала месяца*/
D_END, /*Дата конца месяца*/
SRV_NAME, /*Наименование услуги*/
SPOS_NUM, /*Номер способа расчета - на каждый номер - свой способ*/
CHELNUM, /*Количество проживающих, т.е. задниц*/
SQUARE, /*Площадь - берем из таблицы клиентов*/
OSQUARE, /*Отаплив.площадь - оттуда же*/
[b] DEVICE, /*Вот он, этот чертов СЧЕТЧИК!!!*/[/b]
N_PRICE, /*Тариф*/
PO_TARIFU, /*Расчет по тарифу*/
DEVIACIA, /*Отклонение - если плохо отапливали или воды не было*/
PO_FAKTU, /*По_тарифу - Отклонение*/
LGOTA, /*Льгота*/
SUBSIDYA, /*Субсидия*/
K_OPLATE, /*Окончательно к оплате*/
PENI, /*Пени, ну это от случая к случаю*/
PAYMENT, /*Сколько оплачено*/
N_DATE, /*Дата начмсления*/
TI_NAME /*ЖКУ? Квартплата? Дополнительные услуги? Тип услуг*/
) VALUES (
:opNewID,
:opMID,
:D_BEG,
:D_FIN,
:opSRV_NAME,
:opSPOS_NUM,
:opCHELNUM,
:opSQUARE,/*from TheMain*/
:opOSQUARE,/*from TheMain*/
0,/*opDEVICE*/
:opN_PRICE,
:opPO_TARIFU,
0, /*opDEVIACIA*/
:opPO_TARIFU, /*opPO_FAKTU = opPO_TARIFU,*/
0, /*opLGOTA*/
0, /*opSUBSIDYA*/
0, /*opK_OPLATE*/
0, /*opPENI*/
0, /*opPAYMENT*/
'TODAY', /*opN_DATE*/ /*Тут еще Operator не забыть*/
:OPTI_NAME
);
END
END
SUSPEND;
END
Вот она:
Код: Выделить всё
begin
if (:inspos_num = 2) then /* Если 2 способ - по количеству проживающих - тариф умножить на людей*/
begin
execute procedure pr_sposob2 :inchelnum, :inprice returning_values :outpo_tarifu;
end
else if (:inspos_num = 3) then /* Если 3 способ - по отапливаемой площади - тариф умножить на площадь*/
begin
execute procedure pr_sposob3 :inosquare, :inprice returning_values :outpo_tarifu;
end
/********любой другой способ - все равно вручную, как и в способе №1 **********/
else
begin
execute procedure pr_sposob1 returning_values :outpo_tarifu;
end
suspend;
end
Так вот: если будет способ расчета 4 (по счетчику) - как из этих процедур вызвать его ввод и забрать. Вот чего я добиваюсь-то!
Да. Если отправляют, то уж лучше так, чем прямо по матушке. Не так абыдна.SAMZ писал(а):КАК это сделать - это твоя проблема. Никто за тебя это не решит.
Вот и внешний вид примерно такой: картинка 84 килобайта. У кого инет не халявный - решайте сами. Как видно - слева таблица клиентов, справа - начислений. Ссылка на картинку http://www.l410.h14.ru/ , она в самом верху. Денька через три уберу.
То-есть, примерно то, что и советовал Ivan_Pisarevsky. Ну, там еще есть пара таблиц с тарифами, да способами расчетов, но это не столь важно.
То-есть, примерно то, что и советовал Ivan_Pisarevsky. Ну, там еще есть пара таблиц с тарифами, да способами расчетов, но это не столь важно.
В read_commited через задницу с использованием select for update (если клиентская либа его поддерживает) и дополнительной таблицы в принципе можно, но это полная проктология из любви к искусству, не более того, так что в деталях расписывать не буду, не охота портить человеку жизнь Не надо стремиться писать процедуру типа Обобщённый Решатель Задач. Либо требовать задать все параметры перед расчётом, либо допускать неполный ввод, но тогда считать это как сигнал "а вот это в этот раз считать не надо", либо организовывать логику (или часть её, например, вызывать несколько процедур по очереди с запросом параметров для каждой перед вызовом) на клиенте.
-
- Сообщения: 9
- Зарегистрирован: 17 фев 2005, 15:52
Решение вопроса организации квартир - домов по улицам
Нужно вывести за скобки лицевого счета квартиры указание на адрес квартиры, хранить только указатели на справочники таблицы улиц, номера домов и квартирзахожу я в узел "улица Ленина" - разворачивается куча домов. Тут и запрос с суммами не грех обновить - все равно дома не моментально разворачиваются. Захожу в 1 из домов - там 100 квартир. Тоже обновляю запрос сумм начислений. А потом-то я просто хожу по квартирам курсором.
лицевой счет (или два) - адрес (улица, дом, квартира (если есть),
комната (если есть))
При нужде проводится выборка по связанной таблице
идентификаторов улицы или дома
p.s.
Хорошо бы иметь справочник всех имеющихся в городе домов и квартир, с указанием многоквартирности и проверки полноты и достоверности данных при введении данных на клиенте.
Да-а-а, еще один облом... Ну что мне так не везет, а? Оказывается, FireBird (IB) - тоже не панацея...Лысый писал: Цикл делай на клиенте. Процедура ждать ввода значения не умеет.
Согласен. Тоже считаю, что лучше проще.Merlin писал: Не надо стремиться писать процедуру типа Обобщённый Решатель Задач
Ой, а вот это, наверное, противоречит вышесказанному. Да и, кажется, моя прога и будет первым таким справочником Маленький город, он же - большой поселок. Столица весьма автономного округа с большими амбициями.Александр Коковихин писал: Хорошо бы иметь справочник всех имеющихся в городе домов и квартир, с указанием многоквартирности и проверки полноты и достоверности данных при введении данных на клиенте.
<hr>
Ну ладно, раз нельзя запросить значение счетчика во время процедуры, тогда возникает другой вопрос. Хотя он и без этого возникает:
Вот начисление произведено. Имеем - расчитано значение "PO_TARIFU", и значение "PO_FAKTU". Смысл прост: каждый второй плательщик, стоя в очереди в ЖКХ, начинает скандалить и предъявлять бумаги, что вот тогда-то воды не было, а такого-то отопление выключали... Требование заказчика: дополнительное поле "Отклонение", куда они вводят сумму поправки. Сразу же меняется значение поля "По Факту"= (По Тарифу минус Отклонение). А от поля "По факту" пляшет дальнейший расчет.
Во-о-от. Думаю, это проще считать в триггере. То-есть, если не устраивает начисление, сделанное процедурой, то в уже начисленные строки юзер вводит дополнительные значения: отклонение, показания счетчика, субсидию (они сказали, что будут субсидию считать вручную). Затем делают Post, Refresh - и появляется пересчитанная строка. Но возможно ли узнать, в каком поле было сделано изменение? Следующим требованием клиента (после работы с 1С ) является возможность ручного исправления любого поля на месте, не лазя в настройки, прямо в таблице начислений. Это можно понять: когда на тебя давит орущая очередь, то рассуждения о настройках неуместны.
Исходя из вышесказанного: можно ли узнать, какое поле было изменено, а какое - нет? Понятно, если вручную изменено поле "К Оплате" (акт отчаяния) - то его считать не надо.