|
|
|
Модификация метеденных
|
|||
|---|---|---|---|
|
#18+
Возьмите MSSQL, там все это есть (в смысле - временные таблицы), раз уж Вас с пути не свернуть. И на фига Вам эти SQL - серверы? Вам же предложили варианты решения с временными таблицами. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.12.2003, 15:03 |
|
||
|
Модификация метеденных
|
|||
|---|---|---|---|
|
#18+
Не совсем понял, что означают в вашем отчете "Сумма частная" и "Сумма общая". Если речь идет о следующем: -необходимо знать входящий остаток по счету, дебетовый оборот по счету за период, кредитовый оборот по счету за период, исходящий остаток по счету; -счета с пустыми значениями по всем четырем позициям не должны присутствовать в отчете, тогда попробуйте приспособить под свои нужды примерно следующий план. Главная процедура проходит по всем счетам. Которые не будут участвовать в этом отчете - пропускаются 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 К вопросу о птичках. На мысль о неизбежности использования временных таблиц наводят размышления, исходящие из того, "Что мы имеем". Попробуйте исходить из того, "Что надо получить". Надо получить сортировку по счетам - главный цикл должен идти по таблице счетов. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.12.2003, 20:25 |
|
||
|
Модификация метеденных
|
|||
|---|---|---|---|
|
#18+
На входе в отчёт период и код какого-то одного счёта, по которому нужно получить результат. С периодом - хитрость. Какой бы период не задал пользователь - начало периода перед расчётом надо сбросить в начало года, а пользователю показать сведения за им желаемый период. Первая половинка - в отчёт собираются из журнала операций все обороты по всем счетам по дебету, когда указанный счёт в кредите. Затем вторая половинка - собираются все обороты по всем счетам по кредиту, когда указанный счёт в дебете. Каждая половинка сортируется по месяцам и по номеру счёта. Выясняется количество строк по месяцам в каждой половинке и недостающие заполняются пустыми строками. (Можно и не заполнять математически, но в отчёте должно выглядеть именно так) Сумма частная - это сумма(оборот) за конкретный месяц. Сумма общая - это оборот с начала года. Поэтому в январе по всем счетам частная сумма это оборот по счёту за январь, а общие у всех счетов нули. В феврале у тех счетов, которые встречались в январе - частная сумма будет оборотом за февраль, а общая сумма - оборот за январь плюс оборот за февраль т.е. плюс частная. Те счета, по которым движение началось только в феврале будут иметь только частную сумму, а общая ноль. Если движение по счетам в феврале было, а затем прекратилось, они всё равно должны попасть в отчёт, но все последующие месяцы частная сумма у них будет ноль, а общая постоянная - та которая была последней. Пример чисто условно (без привязки к налоговому кодексу) Журнал 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. Остатки меня не интересуют - они прекрасно вычисляются безо всяких временных таблиц. Обороты тоже вычисляются без временных таблиц, для всех других отчётов, кроме этого. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.12.2003, 08:43 |
|
||
|
Модификация метеденных
|
|||
|---|---|---|---|
|
#18+
>Zmeishe О-о-о ! До боли знакомые вещи ! Делал когда-то. И журналы и оборотно-сальдовые были...:) Тогда я это решал с использованием виртуальной таблицы в памяти. Сейчас я бы это сделал по-другому... Исходя из следующих соображений: 1. Джойнить таблицу можно и саму с собой 2. Использование конструкции SELECT A, (SELECT ...), (SELECT ...) FROM ... Еще не совсем понятно: 1. Зачем выводить по какому-то счету, если движения не было ? 2. Каков критерий, что по этому выводим, а по этому - нет ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.12.2003, 12:58 |
|
||
|
Модификация метеденных
|
|||
|---|---|---|---|
|
#18+
>> 1. Зачем выводить по какому-то счету, если движения не было ? ГОСТ >> 2. Каков критерий, что по этому выводим, а по этому - нет ? Выводим все, которые с заданным счётом корреспондируют либо по дебету либо по кредиту с самого начала года. Остальные счета не нужны. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.12.2003, 13:50 |
|
||
|
Модификация метеденных
|
|||
|---|---|---|---|
|
#18+
Попробуем разработать однопроходную процедуру. Для того чтобы получить данные в виде: Период, Счет Дебета, Сумма частная, Сумма общая, Счет кредита, Сумма частная, Сумма общая, мы создадим промежуточную процедуру. Она выдает данные в следующем виде: Период, Статус(Дебет или Кредит), Счет, Сумма частная, Сумма общая. Например Апрель, Дебет, 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 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.12.2003, 13:57 |
|
||
|
Модификация метеденных
|
|||
|---|---|---|---|
|
#18+
Kata, методология мне ясна, она отличается от моей только тем, что у тебя в одном наборе данных, а у меня в двух физических таблицах. Реализацию анализировать буду только в выходные. Я распечатал твоё предложение. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.12.2003, 14:25 |
|
||
|
Модификация метеденных
|
|||
|---|---|---|---|
|
#18+
Вся фишка в том, что в одной таблице данные по дебету и по кредиту обязательно должны чередоваться. Тогда не надо их никуда скидывать. Поправка Рекурсия не обязательна. Можно двигаться в прямом направлении. Главный цикл по счетам, внутренний по периодам. В примере - вычисление общей суммы засунуть глубже. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.12.2003, 15:24 |
|
||
|
|

start [/forum/topic.php?fid=40&msg=32350669&tid=1579522]: |
0ms |
get settings: |
10ms |
get forum list: |
13ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
176ms |
get topic data: |
10ms |
get forum data: |
2ms |
get page messages: |
47ms |
get tp. blocked users: |
1ms |
| others: | 236ms |
| total: | 503ms |

| 0 / 0 |
