Использование SQL для пропорционального расчета на основе значений DateTime - PullRequest
1 голос
/ 08 июля 2011

Контекст этой проблемы - биллинговая система для склада, в котором хранятся виджеты. Плата за хранение зависит от размера виджета (например, $ x * высота * длина * ширина). Эта часть проста. Я использую следующий SQL для расчета суммы задолженности и агрегирования по идентификатору пользователя.

Select UserID, Sum((Height * Length * Width * 5) as AmtDue From Widget
Where StatusID=2
Group By UserID

5 - произвольное значение на данный момент. В конце концов я передам его в качестве параметра или получу из таблицы в базе данных. Предположим, сейчас всегда 5.

Вот часть, с которой я борюсь. Плата рассчитывается в конце месяца и пропорционально зависит от количества дней в этом месяце, в течение которых виджет хранился на складе (например, если виджет находится на складе в течение 15 дней из 30-дневного месяца, причитающийся сбор составляет 50% от суммы). В моей таблице виджетов у меня есть столбец для DateReceived и DateShipped. DateReceived всегда имеет значение datetime. DateShipped иногда равен нулю (например, если виджет все еще находится в хранилище). У меня есть параметры, доступные для CycleStart и CycleEnd, которые представляют начало и конец соответствующего расчетного месяца. Я пытаюсь изменить свой SQL-запрос, чтобы включить в выражение выбора пропорциональный коэффициент, равный (# дней в хранилище / # дней в месяце). Другими словами, AmtDue становится (высота * длина * ширина * 5 * коэффициент пропорциональности) Как мне это сделать?

Вот пример, помогающий проиллюстрировать, как рассчитывается коэффициент пропорциональности.

Если @CycleStart = 01.07.11 и @CycleEnd = 31.07.11 мм / дд / гг

DateReceived  |  DateShipped  |  Prorate Factor

6/5/11              Null           100%
6/5/11              7/15/11      48.38%
7/30/11             8/5/11        6.45%
7/15/11             7/25/11      35.48%        

Я действительно борюсь с условным характером этого и тем фактом, что мы имеем дело со значениями даты и времени.

Ответы [ 2 ]

2 голосов
/ 08 июля 2011

Вот, пожалуйста. Это

drop table #work
go
create table #work
(
  id           int      not null identity(1,1) primary key clustered ,
  DateReceived datetime not null ,
  DateShipped  datetime     null ,
)
go

insert #work ( DateReceived , DateShipped ) values ( '06/05/2011' , null         )
insert #work ( DateReceived , DateShipped ) values ( '06/05/2011' , '07/15/2011' )
insert #work ( DateReceived , DateShipped ) values ( '07/30/2011' , '08/05/2011' )
insert #work ( DateReceived , DateShipped ) values ( '07/15/2011' , '07/25/2011' )
go

declare
  @CycleStart   datetime ,
  @CycleEnd     datetime ,
  @DaysInPeriod money

set @CycleStart = '07/01/2011'
set @CycleEnd   = '07/31/2011'
set @DaysInPeriod = datediff(day,@CycleStart,dateadd(day,1,@CycleEnd))

select * ,
       DaysInStorage = datediff( day ,
                         case when DateReceived < @CycleStart
                           then @CycleStart
                           else DateReceived
                         end ,
                         case when DateShipped > @CycleEnd
                           then dateadd(day,1,@CycleEnd)
                           else dateadd(day,1,coalesce(DateShipped,@CycleEnd))
                         end
                         ) ,
       DaysInPeriod  = @DaysInPeriod ,
       ProrateFactor = datediff( day ,
                         case when DateReceived < @CycleStart
                           then @CycleStart
                           else DateReceived
                         end ,
                         case when DateShipped > @CycleEnd
                           then dateadd(day,1,@CycleEnd)
                           else dateadd(day,1,coalesce(DateShipped,@CycleEnd))
                         end
                         ) / @DaysInPeriod
from #work

Получает следующее

id DateReceived            DateShipped             DaysInStorage DaysInPeriod ProrateFactor
-- ----------------------- ----------------------- ------------- ------------ -------------
 1 2011-06-05 00:00:00.000 NULL                               30        31.00        1.00
 2 2011-06-05 00:00:00.000 2011-07-15 00:00:00.000            14        31.00        0.4838
 3 2011-07-30 00:00:00.000 2011-08-05 00:00:00.000             1        31.00        0.0645
 4 2011-07-15 00:00:00.000 2011-07-25 00:00:00.000            10        31.00        0.3548
1 голос
/ 08 июля 2011

Попробуйте это:

SELECT CAST(DATEPART( dd,DateShipped) as decimal)/
CAST(DATEPART(dd,DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+1,0))) as decimal) as ProrateFactor

Вы можете умножить на 100, если хотите получить проценты, но я предполагаю, что вы хотите десятичную по соображениям расчета.

Вы можете запустить этот, чтобы увидеть текущий коэффициент пропорциональности:

SELECT CAST(DATEPART( dd,GETDATE()) as decimal)/
CAST(DATEPART(dd,DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+1,0))) as decimal) 

Чтобы свернуть это с текущими расчетами, вы можете сделать это (предупреждение - это отвратительно):

Select UserID, Sum((Height * Length * Width * 5 * 
               SELECT CAST(DATEPART( dd,DateShipped) as decimal)/
               CAST(DATEPART(dd,DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+1,0))) as decimal) ) as AmtDue From Widget
Where StatusID=2
Group By UserID
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...