Запрос для нарастающего итога

Модераторы: kdv, CyberMax

Ответить
kozer
Сообщения: 6
Зарегистрирован: 04 дек 2007, 10:59

Запрос для нарастающего итога

Сообщение kozer » 04 дек 2007, 11:14

Здраствуйте, уважаемые спецы.
Сервер FB 1.5.
В таблице есть 3 поля:
Id - первичный ключ (INTEGER),
DateDoc - дата документа (DATE),
Value - значение (INTEGER).
Нужно сделать запрос (procedure или view), в котором в 4-ом поле будет значение поля Value наростающим итогом за месяц. Кто-нибуть сталкивался с такой задачей?

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Сообщение Dimitry Sibiryakov » 04 дек 2007, 11:56

Stored Procedure - наиболее быстрый и простой путь. Второй по простоте, но первый по скорости - воспользоваться средствами самого отчетника.

kozer
Сообщения: 6
Зарегистрирован: 04 дек 2007, 10:59

Сообщение kozer » 04 дек 2007, 12:01

Нарастающий итог нужен, в первую очередь, для отображения в гриде. А в репорте реализовать без проблем...

CyberMax
Заслуженный разработчик
Сообщения: 638
Зарегистрирован: 31 янв 2006, 09:05

Сообщение CyberMax » 04 дек 2007, 12:58

так?

Код: Выделить всё

select
    ...,
    (select sum(t2.value) from some_table t2 where
        (extract(year from t1.datedoc) = extract(year from t2.datedoc))
        and (extract(month from t1.datedoc) = extract(month from t2.datedoc))
            and (t2.datedoc < t1.date_doc))
from
     some_table t1

kozer
Сообщения: 6
Зарегистрирован: 04 дек 2007, 10:59

Сообщение kozer » 04 дек 2007, 13:09

Спасибо большое, работает!

CyberMax
Заслуженный разработчик
Сообщения: 638
Зарегистрирован: 31 янв 2006, 09:05

Сообщение CyberMax » 04 дек 2007, 14:54

Можешь добавить в таблицы документов поле периода. Тип INTEGER, структура - YYYYMM. Зависит от DateDoc и обновляется либо на клиенте либо в триггере. Позволяет существенно упростить выборку по месяцу и группировку по нему же:
вместо

Код: Выделить всё

WHERE DATEDOC BETWEEN '01.12.2007' AND '31.12.2007'
и

Код: Выделить всё

GROUP BY EXTRACT(YEAR FROM DATEDOC), EXTRACT(MONTH FROM DATEDOC)'
получаем

Код: Выделить всё

WHERE ID_PERIOD = 200712
и

Код: Выделить всё

GROUP BY ID_PERIOD
Ну и плюс прирост скорости выполнения.

belov-evgenii
Сообщения: 52
Зарегистрирован: 28 сен 2007, 10:19

Сообщение belov-evgenii » 04 дек 2007, 15:37

А может что-нибудь типа этого?

Код: Выделить всё

select
    ip.fio_spi as pristav, 
    case when extract(month from current_timestamp) >= 1 then sum(case when ip.date_ip_in < '01.02.2007' then 1 else 0 end) else 0 end as january,
    case when extract(month from current_timestamp) >= 2 then sum(case when ip.date_ip_in < '01.03.2007' then 1 else 0 end) else 0 end as february,
    case when extract(month from current_timestamp) >= 3 then sum(case when ip.date_ip_in < '01.04.2007' then 1 else 0 end) else 0 end as march, 
    case when extract(month from current_timestamp) >= 4 then sum(case when ip.date_ip_in < '01.05.2007' then 1 else 0 end) else 0 end as april, 
    case when extract(month from current_timestamp) >= 5 then sum(case when ip.date_ip_in < '01.06.2007' then 1 else 0 end) else 0 end as may, 
    case when extract(month from current_timestamp) >= 6 then sum(case when ip.date_ip_in < '01.07.2007' then 1 else 0 end) else 0 end as juny, 
    case when extract(month from current_timestamp) >= 7 then sum(case when ip.date_ip_in < '01.08.2007' then 1 else 0 end) else 0 end as july, 
    case when extract(month from current_timestamp) >= 8 then sum(case when ip.date_ip_in < '01.09.2007' then 1 else 0 end) else 0 end as august,
    case when extract(month from current_timestamp) >= 9 then sum(case when ip.date_ip_in < '01.10.2007' then 1 else 0 end) else 0 end as september, 
    case when extract(month from current_timestamp) >= 10 then sum(case when ip.date_ip_in < '01.11.2007' then 1 else 0 end) else 0 end as october, 
    case when extract(month from current_timestamp) >= 11 then sum(case when ip.date_ip_in < '01.12.2007' then 1 else 0 end) else 0 end as november, 
    case when extract(month from current_timestamp) >= 12 then sum(case when ip.date_ip_in < '01.01.2008' then 1 else 0 end) else 0 end as december
from ip
group by 1

kozer
Сообщения: 6
Зарегистрирован: 04 дек 2007, 10:59

Сообщение kozer » 04 дек 2007, 15:57

Нет, спасибо. Насколько я понял, у Вас выводится поле - название месяца и подсчитывается колличество чего-то там за месяц. Немного не то. Уважаемый CyberMax предложил хороший работающий вариант. Я сделал эту задачу при помощи процедур, но предложеный вариант элегантней.

Код: Выделить всё

CREATE PROCEDURE P_GAS 
returns (
    id integer,
    data date,
    fisher integer
)
as
declare variable vYear integer;
declare variable vMonth integer;
begin
  total = 0;
  vYear = 0;
  vMonth = 0;
  for
     select  id,
             data,
             fisher
     from gas
     order by data
     into :id,
           :data,
           :fisher
  do
  begin
  if ((EXTRACT(year from data) <> vYear) or (EXTRACT(month from data) <> vMonth)) then
    begin
     total = 0;
     vYear = EXTRACT(year from data);
     vMonth = EXTRACT(month from data);
    end
    total = total + :fisher;
    suspend;
  end
end

Tonal
Сообщения: 104
Зарегистрирован: 30 сен 2007, 13:42

Сообщение Tonal » 05 дек 2007, 08:48

Можно ещё на контекстных переменных.

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 05 дек 2007, 10:31

Tonal писал(а):Можно ещё на контекстных переменных.
В 1.5 ещё нельзя ;)

Ответить