Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.03.20;
Скачать: CL | DM;

Вниз

Как в хранимой процедуре посчитать среднехронологические значения   Найти похожие ветки 

 
AlexandrKu   (2005-02-18 11:01) [0]

Есть
база типа
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


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

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. Вроде, всё.


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

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


 
MOA ©   (2005-02-18 12:03) [3]

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

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;

Удачи!


 
MOA ©   (2005-02-18 12:05) [4]

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


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

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


 
MOA ©   (2005-02-18 12:35) [6]

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

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 - если подобных вычислений много, может оказаться разумным ;).
Удачи!


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

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


 
Ega23 ©   (2005-02-18 12:42) [8]

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

При чём тут BDE?


 
MOA ©   (2005-02-18 12:42) [9]

Чёрт. В приведённом моём скрипте пропущены везде связи по 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)

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


 
MOA ©   (2005-02-18 12:47) [10]

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


 
MOA ©   (2005-02-18 12:50) [11]

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


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

Делай так:

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


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

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


 
Ega23 ©   (2005-02-18 13:03) [14]

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


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

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


 
Ega23 ©   (2005-02-18 13:54) [16]

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

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

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

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


 
Ega23 ©   (2005-02-18 13:56) [17]

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


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

Вообщем в 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;

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



Страницы: 1 вся ветка

Текущий архив: 2005.03.20;
Скачать: CL | DM;

Наверх




Память: 0.51 MB
Время: 0.063 c
1-1109921070
Оля
2005-03-04 10:24
2005.03.20
Чтение строки из TMemorystream


14-1109325132
Cosinus
2005-02-25 12:52
2005.03.20
У Подгорецкого на сайте была статья по работе с битами.


6-1106208547
xZero
2005-01-20 11:09
2005.03.20
бродкаст через хабы


4-1107884471
Фдуч
2005-02-08 20:41
2005.03.20
Что значит Port 60/64?


9-1103729660
-=SS=-
2004-12-22 18:34
2005.03.20
GlScene Тень