![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как в хранимой процедуре посчитать среднехронологические значения [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. Вроде, всё.