使用SQL根据DateTime值进行按比例分配

时间:2011-07-08 16:27:18

标签: sql sql-server sql-server-2008

此问题的上下文是存储小部件的仓库的计费系统。存储费用基于小部件的大小(例如$ x * height * length * width)。这部分很容易。我使用以下SQL来计算Amount Due,并按用户ID汇总。

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

5是当下的任意值。最终我将它作为参数传递或从数据库中的表中获取它。假设它现在总是5。

这是我正在努力的部分。费用是在月末计算的,并根据小部件存储在仓库中的那个月的天数进行按比例分配(例如,如果小部件在30天内在仓库中停留15天,则应付费用为50%的金额)。在我的Widget表中,我有一个DateReceived和DateShipped列。 DateReceived始终具有日期时间值。 DateShipped有时为null(例如,如果窗口小部件仍在存储中)。我有可用于CycleStart和CycleEnd的参数,它们代表相关结算月份的开始和结束。我正在尝试修改我的SQL查询,以在select表达式中包含一个等于(存储天数/月中天数)的比例因子。换句话说,AmtDue变为(高度*长度*宽度* 5 *比例因子)我该怎么做?

这是一个帮助说明如何计算比例因子的例子。

如果@CycleStart = 7/1/11且@CycleEnd = 7/31/11 mm / dd / yy

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 个答案:

答案 0 :(得分:2)

你走了。此

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 :(得分:1)

试试这个:

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