2011-07-08 27 views
1

此問題的上下文是存儲小部件的倉庫的計費系統。存儲費用基於widget的大小(例如$ x * height * length * width)。這部分很簡單。我使用以下SQL來計算到期金額和按用戶ID彙總。使用SQL根據DateTime值進行比例分解

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有時爲空(例如,如果小部件仍在存儲中)。我有可用於CycleStart和CycleEnd的參數,這些參數代表相關開票月份的開始和結束。我試圖修改我的SQL查詢,以在選擇表達式中包含等於(存儲天數/月的#天數)的分攤比例。換句話說,AmtDue變成(高度*長度*寬度* 5 *比例因子)我該怎麼做?

下面是幫助說明如何計算比例因子的示例。

如果@CycleStart = 11年7月1日和@CycleEnd = 11年7月31日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%   

我真的有這種條件的性質和事實掙扎,我們正在處理日期時間值。

+0

我們能總是假設每月30天? – gbn

+0

我們可以,如果它大大簡化了事情。否則,我寧願準確地使用相關月份的實際天數。 – hughesdan

回答

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 
+0

太棒了。我假設你打算宣佈DaysInPeriod是一個整數而不是金錢。 – hughesdan

+0

是的。作爲'int',它會自動向上轉換(擴大轉換)。儘管如此,沒有什麼可以阻止你聲明'@ DaysInPeriod'是一個'money'值。 –

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 
+0

謝謝,這看起來像是在正確的軌道上。但是,按照指示修改我的Select語句會導致我的Group By語句出現問題。特別是,SQL期望在這些列上進行某種聚合。你有什麼建議? – hughesdan

+0

爲了使這項工作在當前月份以外的某個月進行,將@DYDATE()替換爲@CycleEnd是否正確? – hughesdan

+0

如果您使用GETDATE(),它將僅適用於當前月份。如果您想要的是當前月份以外的內容,您應該可以用@ CycleStart/@ CycleEnd代替。您需要在GROUP BY語句中包含所選的新列,才能使其工作。 –