powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Модификация метеденных
8 сообщений из 33, страница 2 из 2
Модификация метеденных
    #32349342
Фотография mv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Возьмите MSSQL, там все это есть (в смысле - временные таблицы), раз уж Вас с пути не свернуть. И на фига Вам эти SQL - серверы?
Вам же предложили варианты решения с временными таблицами.
...
Рейтинг: 0 / 0
Модификация метеденных
    #32349870
kata
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Не совсем понял, что означают в вашем отчете
"Сумма частная" и "Сумма общая".
Если речь идет о следующем:
-необходимо знать входящий остаток по счету,
дебетовый оборот по счету за период,
кредитовый оборот по счету за период,
исходящий остаток по счету;
-счета с пустыми значениями по всем четырем позициям
не должны присутствовать в отчете,
тогда попробуйте приспособить под свои нужды примерно следующий план.


Главная процедура проходит по всем счетам.
Которые не будут участвовать в этом отчете - пропускаются
create procedure GetMoveAndRestReport(
BeginDate Date,
EndDate Date)
returns (
Account Integer,
BeginRest Double Precision,
DebitMove Double Precision,
KreditMove Double Precision,
EndRest Double Precision)
as
declare variable DebitRest Double Precision;
declare variable KreditRest Double Precision;
begin
for select a.ID from Account a
into :Account
do begin
/* вычисляем входящий остаток по счету */
select Sum(m.Summa) from Move m
where m.Debit = :Account and m.Oper_date < :BeginDate
into :DebitRest;
if (DebitRest is null) then DebitRest = 0;
select Sum(m.Summa) from Move m
where m.Kredit = :Account and m.Oper_date < :BeginDate
into :KreditRest;
if (KreditRest is null) then KreditRest = 0;
BeginRest = DebitRest - KreditRest;
/* вычисляем дебетовый оборот по счету за период */
select Sum(m.Summa) from Move m
where m.Debit = :Account and m.Oper_date between :BeginDate and :EndDate
into :DebitMove;
if (DebitMove is null) then DebitMove = 0;
/* кредит */
select Sum(m.Summa) from Move m
where m.Kredit = :Account and m.Oper_date between :BeginDate and :EndDate
into :KreditMove;
if (KreditMove is null) then KreditMove = 0;
if ((BeginRest <> 0) or (DebitMove <> 0 ) or (KreditMove <> 0)) then begin
/* исходящий */
EndRest = BeginRest + DebitMove - KreditMove;
suspend;
end
end
end

Вот такие получаются результаты
select * from Account
ID
===========
1
2
3
4
5
6
7
8
9
10

select * from Move
ID OPER_DATE DEBIT KREDIT SUMMA
=========== =========== =========== =========== ======================
1 1-JAN-2003 1 2 100
2 2-JAN-2003 1 3 101
3 20-JAN-2003 2 3 102
4 18-JAN-2003 5 6 103
5 19-JAN-2003 5 2 104

select * from GetMoveAndRestReport('15-JAN-2003','30-JAN-2003')
ACCOUNT BEGINREST DEBITMOVE KREDITMOVE ENDREST
=========== ====================== ====================== ====================== ======================
1 201 0 0 201
2 -100 102 104 -102
3 -101 0 102 -203
5 0 207 0 207
6 0 0 103 -103


К вопросу о птичках.
На мысль о неизбежности использования временных таблиц наводят размышления,
исходящие из того, "Что мы имеем".
Попробуйте исходить из того, "Что надо получить".
Надо получить сортировку по счетам - главный цикл должен идти по таблице счетов.
...
Рейтинг: 0 / 0
Модификация метеденных
    #32350046
Фотография Zmeishe
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
На входе в отчёт период и код какого-то одного счёта, по которому нужно получить результат. С периодом - хитрость. Какой бы период не задал пользователь - начало периода перед расчётом надо сбросить в начало года, а пользователю показать сведения за им желаемый период.

Первая половинка - в отчёт собираются из журнала операций все обороты по всем счетам по дебету, когда указанный счёт в кредите.
Затем вторая половинка - собираются все обороты по всем счетам по кредиту, когда указанный счёт в дебете.

Каждая половинка сортируется по месяцам и по номеру счёта. Выясняется количество строк по месяцам в каждой половинке и недостающие заполняются пустыми строками. (Можно и не заполнять математически, но в отчёте должно выглядеть именно так)

Сумма частная - это сумма(оборот) за конкретный месяц.
Сумма общая - это оборот с начала года.
Поэтому в январе по всем счетам частная сумма это оборот по счёту за январь, а общие у всех счетов нули.

В феврале у тех счетов, которые встречались в январе - частная сумма будет оборотом за февраль, а общая сумма - оборот за январь плюс оборот за февраль т.е. плюс частная.
Те счета, по которым движение началось только в феврале будут иметь только частную сумму, а общая ноль.

Если движение по счетам в феврале было, а затем прекратилось, они всё равно должны попасть в отчёт, но все последующие месяцы частная сумма у них будет ноль, а общая постоянная - та которая была последней.

Пример чисто условно (без привязки к налоговому кодексу)
Журнал
05.01.2003 Дт-51 Кт-60 1000 р
07.01.2003 Дт-50 Кт-51 500 р
09.02.2003 Дт-48 Кт-51 100 р

Отчёт по счёту 51
Код: plaintext
1.
2.
3.
4.
5.
Первая половинка (Дт)       |  Вторая половинка (Кт)
Январь
 60  частная  1000  р общая  0  р |   50  частная  500  р общая  0  р
Февраль 
 60  частная  0  р общая  1000  р |   48  частная  100  р общая  0  р
   <null>                   |   50  частная  0  р   общая  500  р

Остатки меня не интересуют - они прекрасно вычисляются безо всяких временных таблиц.
Обороты тоже вычисляются без временных таблиц, для всех других отчётов, кроме этого.
...
Рейтинг: 0 / 0
Модификация метеденных
    #32350546
Фотография Johnmen
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
>Zmeishe

О-о-о ! До боли знакомые вещи !
Делал когда-то. И журналы и оборотно-сальдовые были...:)
Тогда я это решал с использованием виртуальной таблицы в памяти.
Сейчас я бы это сделал по-другому... Исходя из следующих соображений:
1. Джойнить таблицу можно и саму с собой
2. Использование конструкции SELECT A, (SELECT ...), (SELECT ...) FROM ...

Еще не совсем понятно:
1. Зачем выводить по какому-то счету, если движения не было ?
2. Каков критерий, что по этому выводим, а по этому - нет ?
...
Рейтинг: 0 / 0
Модификация метеденных
    #32350669
Фотография Zmeishe
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
>> 1. Зачем выводить по какому-то счету, если движения не было ?
ГОСТ

>> 2. Каков критерий, что по этому выводим, а по этому - нет ?
Выводим все, которые с заданным счётом корреспондируют либо по дебету либо по кредиту с самого начала года. Остальные счета не нужны.
...
Рейтинг: 0 / 0
Модификация метеденных
    #32350686
kata
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Попробуем разработать однопроходную процедуру.
Для того чтобы получить данные в виде:
Период, Счет Дебета, Сумма частная, Сумма общая, Счет кредита, Сумма частная, Сумма общая,
мы создадим промежуточную процедуру.
Она выдает данные в следующем виде:
Период, Статус(Дебет или Кредит), Счет, Сумма частная, Сумма общая.
Например
Апрель, Дебет, 50, 100, 300
Апрель, Кредит, 48, 200, 500
Апрель, Дебет, 60, 0, 100
Апрель, Кредит, 61, 20, 90
Апрель, Кредит, 70, 0, 30
Дебет и Кредит при этом ОБЯЗАТЕЛЬНО должны чередоваться,
тогда главная процедура растолкает их по нужным местам в один проход.
Проблема: для того, чтобы получить общие данные, необходим рекурсивный
вызов для предыдущего периода. Например, между первой и второй строкой
Апрель, Дебет, 50, 100, 300
Апрель, Кредит, 48, 200, 500
могут быть такие данные:
Март, Дебет, 50, 100, 200
Февраль, Дебет, 50, 100, 0
При этом нарушается чередование Дебета и Кредита
(То, что нарушается порядок по периодам -
не проблема, так как промежуточный результат можно еще раз отсортировать)
Решение: вводим еще одно поле - идентификатор записи, и для этого поля
два счетчика - отдельно для дебита и кредита. Причем для каждого периода
своя пара счетчиков - итого 24 счетчика. Инкремент для них = 2. Значения
по дебету всегда нечетные, значения по кредиту - всегда четные
Получаем промежуточные данные в следующем виде:
1, Апрель, Дебет, 50, 100, 300
1, Март, Дебет, 50, 100, 200
1, Февраль, Дебет, 50, 100, 0
2, Апрель, Кредит, 48, 200, 500
2, Март, Кредит, 48, 300, 0
3, Апрель, Дебет, 60, 0, 100
3, Март, Дебет, 60, 100, 0
4, Апрель, Кредит, 61, 20, 90
4, Март, Кредит, 61, 20, 70
2, Февраль, Кредит, 61, 25, 25
2, Январь Кредит, 61, 25, 0
6, Апрель, Кредит, 70, 0, 30
6, Март, Кредит, 70, 30, 0

После сортировки по полям Период, Идентификатор:
2, Январь Кредит, 61, 25, 0
1, Февраль, Дебет, 50, 100, 0
2, Февраль, Кредит, 61, 25, 25
1, Март, Дебет, 50, 100, 200
2, Март, Кредит, 48, 300, 0
3, Март, Дебет, 60, 100, 0
4, Март, Кредит, 61, 20, 70
6, Март, Кредит, 70, 30, 0
1, Апрель, Дебет, 50, 100, 300
2, Апрель, Кредит, 48, 200, 500
3, Апрель, Дебет, 60, 0, 100
4, Апрель, Кредит, 61, 20, 90
6, Апрель, Кредит, 70, 0, 30

Вот и всё!

Вот вариант многопроходной процедуры.
Если отчет делается за декабрь, то по данным за январь будет 12 проходов
В принципе разницы нет между 1 секундой и 12-ю.

create procedure Get1971BurnedReport (
Account Integer,
TheMonth Integer,
TheYear Integer)
returns (
BeginDate Date,
EndDate Date,
DebitAccount Integer,
DebitPrivate Double Precision,
DebitPublic Double Precision,
KreditAccount Integer,
KreditPrivate Double Precision,
KreditPublic Double Precision)
as
declare variable CurrentMonth Integer;
declare variable DebitRingStop Smallint;
declare variable KreditRingStop Smallint;
declare variable CurrentDebitAccount Integer; /* зеркало для непустых значений */
declare variable CurrentKreditAccount Integer;
begin
/* главный цикл по периодам */
CurrentMonth = 1;
while (CurrentMonth <= TheMonth) do begin
select begindate, enddate from CalcPeriod(:CurrentMonth,:TheYear) into :BeginDate,:EndDate;
/* внутренний цикл по счетам */
select * from GetFirstAccount into :FirstAccount;
select * from GetLastAccount into :LastAccount;
DebitRingStop = 0;
KreditRingStop = 0;
CurrentDebitAccount = FirstAccount;
CurrentKreditAccount = FirstAccount;
while ((DebitRingStop = 0) and (KreditRingStop = 0)) do begin
/* очищаем значения перед печатью */
DebitAccount = null;
DebitPrivate = null;
/* бежим по всем счетам пока не находим первый, */
/* у которого не пустые обороты */
while ((DebitAccount is null) and (CurrentDebitAccount <= LastAccount) and
(DebitRingStop = 0)) do begin
/* вычисляем обороты за период */
select * from GetMove(:BeginDate,:EndDate,:Account,:CurrentDebitAccount) into :DebitPrivate;
/* если проверили последний счет, то пора выходить из цикла */
if (CurrentDebitAccount = LastAccount) then DebitRingStop = 1;
else begin
/* заполняем значение */
if (DebitPrivate > 0) then DebitAccount = CurrentDebitAccount;
/* двигаемся к следующему счету */
select * from GetNextAccount(:CurrentDebitAccount) into :CurrentDebitAccount;
end
end
/* вычисляем общую сумму */
DebitPublic = null;
select * from GetMove('01.01.'||TheYear,:BeginDate-1,:Account,:DebitAccount)
into :DebitPublic;
if ((DebitPublic > 0) and (DebitPrivate > 0)) then DebitPublic = DebitPublic + DebitPrivate;
/* аналогично для кредита */
suspend;
end
CurrentMonth = CurrentMonth + 1;
end
end
...
Рейтинг: 0 / 0
Модификация метеденных
    #32350762
Фотография Zmeishe
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Kata, методология мне ясна, она отличается от моей только тем, что у тебя в одном наборе данных, а у меня в двух физических таблицах.
Реализацию анализировать буду только в выходные. Я распечатал твоё предложение.
...
Рейтинг: 0 / 0
Модификация метеденных
    #32350856
kata
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Вся фишка в том, что в одной таблице данные по дебету и по кредиту обязательно должны чередоваться. Тогда не надо их никуда скидывать.
Поправка
Рекурсия не обязательна. Можно двигаться в прямом направлении. Главный цикл по счетам, внутренний по периодам.
В примере - вычисление общей суммы засунуть глубже.
...
Рейтинг: 0 / 0
8 сообщений из 33, страница 2 из 2
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Модификация метеденных
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]