Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Как в хранимой процедуре посчитать среднехронологические значения [D5, MSSQL]


AlexandrKu ©   (2005-02-18 11:01:00) 

Есть
база типа
account, date_carry, rest
400000,'12.02.2005',135
400001,'25.10.2004',3000
400001,'28.10.2004',1800
400001,'29.10.2004',7800
Необходимо посчитать по счету 400001 таким образом:
1. виртуально обавить недастоющие дни (25,26)
400001,'25.10.2004',3000
400001,'26.10.2004',3000
400001,'27.10.2004',3000
400001,'28.10.2004',1800
400001,'29.10.2004',7800
2. посчитать сумму остатков и разделить на количество дней (5)
пока дошел вот до чего

CREATE PROCEDURE Dbo.RestA
@account varchar(20) ,
@Datebeg Datetime,
@dateend datetime,
@rest  int output

AS
declare
@days integer;
set  @days=0;
While @datebeg<=@dateend
begin
        select  top 1 @rest=@rest+rest
          from restdate
       where (account=@account) and (Date_carry<=@datebeg)
     order by  date_carry desc;
  set @Datebeg=@Datebeg+1;
  set @days=@days+1;
end;
set @rest=@rest/@days;
return @rest;
GO

процедура выдает 0


AlexandrKu   (2005-02-18 14:01:00) [1]

Вообщем в QA все выполняется а в дельфях неберет точнее возвращает 0
ADOStoredProc1.Parameters.ParamByName('@account').value:='70209810700012941602';
ADOStoredProc1.Parameters.ParamByName('@datebeg').value:=DateTimePicker1.DateTime;
ADOStoredProc1.Parameters.ParamByName('@dateend').value:=DateTimePicker2.DateTime;
ADOStoredProc1.ExecProc;
s:=ADOStoredProc1.Parameters.ParamByName('@rest').Value;

Всегда работало (точнее раньше) а сейчас что-то неполучается :(


Ega23   (2005-02-18 13:56:00) [2]

Слушай, я от сетки сейчас отключусь, если есть вопросы - пиши на egorov@dedal.dubna.ru, ОК?


Ega23   (2005-02-18 13:54:00) [3]

Да, вернёшь. Но всё зависит от того, КУДА ты этот результат хочешь получить.
Если на клиент - то проще перед Return поставить Select Rest=@Rest

На клиенте:
Query.SQL.Text:='exec S_MyProc ....';
Query.Open;
Result:=Query.FieldByName('Rest').asFloat;

Если ты эту процедуру из другой ХП хочешь использовать, то тогда лучше через output.

Вариантов много...


AlexandrKu   (2005-02-18 13:15:00) [4]

Т.е. заголовок процедуры:
CREATE PROCEDURE Dbo.RestA
@account varchar(20) ,
@Datebeg Datetime,
@dateend datetime,
@rest  float output???
Return @rest -убрать,
таким образом я же верну значение?


Ega23   (2005-02-18 13:03:00) [5]

return у тебя ТОЛЬКО int вернуть может.
Делай выводы...


AlexandrKu   (2005-02-18 12:55:00) [6]

2 MOA QA выдавало NULL и в приложении 0
Нашел ошибку всем спасибо
просто переменную @rest непроинициализировал и он нехотел прибавлять туда результат
перед циклом добавил set @rest=0  и все пошло
еще раз спасибо MOA за то что открыл глаза на тип @rest действительно нужен float


Ega23   (2005-02-18 12:51:00) [7]

Делай так:

Declare @X int
Set NoCount ON
exec @X=S_MyProc ...
Set NoCount OFF
Select X=@X


MOA   (2005-02-18 12:50:00) [8]

Описка.
MIN(r4.Date_carry) => MAX(r4.Date_carry)


MOA   (2005-02-18 12:47:00) [9]

>При чём тут BDE?
Ну, на первый взгляд - процедура автора рабочая. Я попробовал нечто похожее - работает. Разве что поставить вместо rest ISNULL(rest,0).
Кстати, сам тоже забыл эту штуку :(.
Однако, вопрос автору: 0 выдаётся в QA? Или в приложении?


MOA   (2005-02-18 12:42:00) [10]

Чёрт. В приведённом моём скрипте пропущены везде связи по account. Вот:
SELECT
SUM(ALL
CASE DATEDIFF(day, r1.Date_carry, r2.Date_carry)
 WHEN 1 THEN r1.rest
 ELSE r1.rest * DATEDIFF(day, r1.Date_carry, r2.Date_carry)
END)
FROM restdate r1 LEFT OUTER JOIN restdate r2
ON (r2.account=@account)
AND (r2.Date_carry = (SELECT MIN(r3.Date_carry) FROM restdate r3 WHERE (r3.Date_carry > r1.Date_carry) AND (r3.account=@account)))
WHERE (r1.Date_carry >= (SELECT MIN(r4.Date_carry) FROM restdate r4 WHERE (r4.Date_carry <= @Datebeg) AND (r4.account=@account)))
AND (r1.Date_carry <= @dateend) AND (r1.account=@account)

Приношу свои извинения :(.


Ega23   (2005-02-18 12:42:00) [11]

Дело в том, что в BDE (вроде) припоминается мне глюк - результат процедуры всегда 0 :(.

При чём тут BDE?


MOA   (2005-02-18 12:36:00) [12]

Да, и по поводу 0 -то ;) - с датасетом не проходит?.
Дело в том, что в BDE (вроде) припоминается мне глюк - результат процедуры всегда 0 :(.


MOA   (2005-02-18 12:35:00) [13]

Придумал без цикла (не проверял!):

set  @days=DATEDIFF(day, @datebeg, @dateend)

SELECT
SUM(ALL
CASE DATEDIFF(day, r1.Date_carry, r2.Date_carry)
 WHEN 1 THEN r1.rest
 ELSE r1.rest * DATEDIFF(day, r1.Date_carry, r2.Date_carry)
END)
FROM restdate r1 LEFT OUTER JOIN restdate r2
ON (r2.Date_carry = (SELECT MIN(r3.Date_carry) FROM restdate r3 WHERE r3.Date_carry > r1.Date_carry))
WHERE (r1.Date_carry >= (SELECT MIN(r4.Date_carry) FROM restdate r4 WHERE r4.Date_carry <= @Datebeg))
AND (r1.Date_carry <= @dateend)

set @rest=@rest/@days

CASE не обязателен ;). Нужно, впрочем, попробовать, что быстрее - всегда умножать даже и на 1, или проверять как тут ;).
Ещё вариант - сформировать таблицу дней и делать запрос с OUTER JOIN - если подобных вычислений много, может оказаться разумным ;).
Удачи!


AlexandrKu   (2005-02-18 12:23:00) [14]

реально я их невставляю я получаю значение остатка в этот день (если записи нет то берется предидущий остаток)


MOA   (2005-02-18 12:05:00) [15]

А, понял! Вы так вставляете пропущенные остатки. Моё предыдущее исправление неворно. Сейчас подумаю тщательнее ;)..


MOA   (2005-02-18 12:03:00) [16]

Попробуйте - вместо

return @rest

вот так:

SELECT @rest AS F_rest

и результат - в датасете.
Так - не ноль?

PS. Я бы написал (не вдаваясь (не меняя) алгоритм, поскольку не совсем ясна задача, например почему res - целое)

set  @days=DATEDIFF(day, @datebeg, @dateend);
While @datebeg<=@dateend
begin
SELECT @rest=@rest+rest
 from restdate
      where (account=@account) and (Date_carry=@datebeg)
 set @Datebeg=@Datebeg+1;
end;

Удачи!


AlexandrKu   (2005-02-18 11:54:00) [17]

в данном случае насколько я понимаю он посчитает сумму за 3 дня а нужно за 5


Ega23   (2005-02-18 11:12:00) [18]

1. Declare @DatIn datetime, @datOut datetime, @SumRest int, @Result  float
2. Set @DatIn='25.10.2004'  Set @DatOut='29.10.2004'
3. Select @sumRest=Sum(rest)  from restdate where date_Carry between(@DatIn, @DatOut)
5. Select @Result=@SumRest/((Cast(@DatOut) as int) - (Cast(@DarIn) as int))
6. Вроде, всё.


Наверх

Титульная страница Поиск, карта сайта Написать письмо