2012-02-01 8 views
1

前月の各顧客の最後の3取引の合計金額を取得する必要があります。今日は2012/1/31だとしましょう。前月の各顧客の最後の3取引の合計金額を取得する

使用しているアプローチを使用する理由について、ステップバイステップの回答を提供してください。

たとえば、私が考えた答えがここにあります。それは間違っているかもしれない。

  1. (選択トップ3を使用して)、前の月の顧客の最後の3つの取引を取得するには、内側のクエリを作成しますCustomerNameの
  2. によってCustomerTransactionテーブル群を反復処理するためにカーソルを作成し、一時的にそれを挿入テーブル
  3. 一時テーブル内の結果を選択して合計(金額)を取得し、それをCustomerNameでグループ化します。

だから私は、これらの列を持つCustomerTransactionテーブルを持っている:あなたがそれを必要とする場合はここで

ID, CustomerName, Amount, TransactionDate 

はスクリプトです。私は結果をテストするためにそれを使用しています。

insert into Test.dbo.CustomerTransaction (CustomerName, Amount, TransactionDate) 
values ('John', 100.0, '2011-12-31'), 
('John', 100.0, '2011-12-30'), 
('John', 100.0, '2011-12-29'), 
('John', 100.0, '2011-12-28'), 
('Boyd', 100.0, '2011-12-30'), 
('Boyd', 200.0, '2011-12-29'), 
('Boyd', 100.0, '2011-12-28'), 
('Boyd', 100.0, '2011-12-27') 
+0

これまでにお試しいただいた内容は何ですか? – peroija

+0

次回は、あなたのソリューションの一部としてカーソルを使用すると思いますが、自分自身を好きにしてください。 –

答えて

2

私自身がクロスアプライを好む&簡単にするために、上の組み合わせ。

更新日 - 日付範囲の計算を修正しました。また

- あなたはどちらか、決定論的SELECT TOP N WITH TIESメソッドを使用するか、SELECT TOPクエリのORDER BY句に主キーまたは「uniquifier」のいくつかの種類を追加するクエリが必要な場合。

DECLARE @fd AS DATETIME; 
DECLARE @ld AS DATETIME; 
SET @fd = (dateadd(month, datediff(month, -1, getdate()) - 2, -1) + 1); 
SET @ld = dateadd(month, datediff(month, -1, getdate()) - 1, -1); 

WITH Customers AS (
    SELECT CustomerName 
    FROM tempdb.dbo.CustomerTransaction 
    GROUP BY CustomerName 
) 
SELECT C.CustomerName, 
     SUM(Amount) AS Total 
FROM Customers AS C 
CROSS APPLY (
    SELECT TOP (3) Amount 
    FROM tempdb.dbo.CustomerTransaction AS T 
    WHERE TransactionDate BETWEEN @fd AND @ld 
     AND T.CustomerName = C.CustomerName 
    ORDER BY TransactionDate DESC 
) Q 
GROUP BY C.CustomerName; 

結果:

CustomerName Total 
------------ --------------------------------------- 
Boyd   400.00 
John   300.00 
0

これは楽しいものでした。ステップバイ

http://sqlfiddle.com/#!3/ae6fd/20

with lastMonth as 
    (

    select * from CustomerTransaction 
    where 
    TransactionDate >= DateAdd(m, -1, cast(cast(month(getdate()) as varchar) + '/1/' + cast(year(getdate()) as varchar) as date)) AND 

    TransactionDate < cast(cast(month(getdate()) as varchar) + '/1/' + cast(year(getdate()) as varchar) as date) 
) 


select 
    customerName, 
    sum(Amount) as total 
from 
lastMonth lm 
where 
    not exists (

    select 1 from lastMonth lm2 
    WHERE lm2.customerName = lm.customerName AND 
     exists (
     select 1 from lastMonth lm3 
     WHERE lm3.customerName = lm2.customerName AND 
       exists (
       select 1 from lastMonth lm4 
       WHERE lm4.customerName = lm3.customerName AND 
       lm4.TransactionDate > lm3.TransactionDate 
      ) AND 
       lm3.TransactionDate > lm2.TransactionDate 
    ) AND 
     lm2.TransactionDate > lm.TransactionDate 

) 
group by 
    customerName 

ステップ私はこのようにそれをしなかった理由は:

LastMonth CTEように、私は、パフォーマンスと可読性のために両方、繰り返し基本データセットをフィルタリングする必要はありません。

最後の3つの値は、存在しない+存在するチェーンによって達成されます。これらは、lastMonthからのデータをフィルタリングして、3つのレコードのみが返されるようにします(3回のジョインを介して行われます)。

+0

全開示:sqlfiddle.comは私のサイト –

+0

同じ日付のテーブルにもう1つのトランザクションを追加すると、 1つの取引。したがって、上位3位になるのではなく、上位4位(同じ取引日の1つの取引を含む)になります。 'CustomerTransaction(CustomerName、Amount、TransactionDate)に値を挿入する( 'John'、100.0、 '2011-12-29') ' – Wisp

+0

本当に、トランザクションの日付は基本的にタイムスタンプであり、 –

0
declare @d datetime = '2012-01-31' 

declare @CustomerTransaction table(CustomerName varchar(10), Amount money, TransactionDate datetime) 

insert into @CustomerTransaction 
(CustomerName, Amount, TransactionDate) 
values ('John', 100.0, '2011-12-31'), 
('John', 100.0, '2011-12-30'), ('John', 100.0, '2011-12-29'), 
('John', 100.0, '2011-12-28'), ('Boyd', 100.0, '2011-12-30'), 
('Boyd', 200.0, '2011-12-29'), ('Boyd', 100.0, '2011-12-28'), 
('Boyd', 100.0, '2011-12-27') 

;with cte as 
(
select CustomerName, Amount, TransactionDate, 
rn = row_number() over (partition by customername order by transactiondate desc) 
from @CustomerTransaction--replace with: from Test.dbo.CustomerTransaction 
where datediff(month, TransactionDate, @d) = 1 
) 
select CustomerName, Amount, TransactionDate 
from cte where rn < 4 
1

私は答えはまだ間違っていると思うが、非常に近いです。それはまだ最後の日を逃す。
月の最終日の午前12時00分は、前日の終わりです。 最後の1日を含めるには、11:59:59までにする必要があります。999 PM

DECLARE @fd AS TIMEDATE; 
DECLARE @ld AS TIMEDATE; 

SET @fd = (dateadd(month, datediff(month, -1, getdate()) - 2, -1) + 1); 
SET @ld = (dateadd(ms, -2, dateadd(month, datediff(month, -1, getdate()) - 1, -1) + 1)); 

PRINT @fd 
PRINT @ld 
関連する問題