2011-07-08 2 views
1

この問題のコンテキストは、ウィジェットを格納するウェアハウスの請求システムです。保存料はウィジェットのサイズに基づいています(例:$ x * height * length * width)。この部分は簡単です。 Amount Dueを計算するために次の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%)。私のウィジェットテーブルには、DateReceivedとDateShippedの列があります。 DateReceivedには常にdatetime値があります。 DateShippedがnullであることがあります(ウィジェットがまだ格納されている場合など)。 CycleStartとCycleEndに使用可能なパラメータは、関連する請求月の開始日と終了日を表します。私は選択式に(ストレージの日数/月の#)と等しい比率係数を含めるようにSQLクエリを変更しようとしています。言い換えると、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%   

場合datetime値を扱っています。

+0

たちは30日の月は常に前提とすることはできますか?利回り – gbn

+0

事を大幅に簡略化すれば可能です。そうでなければ、私は正確で、関連する月の実際の日数を使用することを好むでしょう。 – hughesdan

答えて

2

ここで: - (それは恐ろしいです警告)

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

は、あなたがこれを行うことができますあなたの現在の計算とそれをロールバックする:

あなたは、今日の比例配分率を表示するには、このいずれかを実行することができます行く。この

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をお金ではなくintとして宣言することを前提としています。 – 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 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

ありがとう、これは右のトラックにあるように見えます。ただし、私の選択ステートメントを指定したように変更すると、私のGroup Byステートメントで問題が発生しています。具体的には、SQLはこれらの列にある種の集約を期待しています。何を指示してるんですか? – hughesdan

+0

今月以外の月にこの作品を作成するには、@CycleEndの代わりにGETDATE()を使用するのが正しいでしょうか? – hughesdan

+0

GETDATE()を使用すると、現在の月のみで動作します。現在の月以外のものが必要な場合は、@ CycleStart/@ CycleEndに置き換えることができます。この作業を行うには、GROUP BY文で選択されている新しい列を含める必要があります。 –

関連する問題