获取上个月每位客户最后3笔交易的总金额

时间:2012-02-01 02:47:46

标签: sql sql-server-2005 tsql

我需要获得上个月每位客户最近3笔交易的总金额。我们今天说的是2012/1/31。

请逐步解答您使用所用方法的原因。

例如,这是我想到的答案。这可能是错的。

  1. 创建游标以按CustomerName
  2. 遍历CustomerTransaction表组
  3. 创建内部查询以获取上个月客户的最后3笔交易(使用选择前3位),将其插入临时表
  4. 在临时表中选择结果并获取总和(金额)并按客户名对其进行分组。
  5. 所以我有一个包含以下列的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')
    

4 个答案:

答案 0 :(得分:2)

我自己更喜欢Cross Apply&最简单的组合。

更新 - 我已修复日期范围计算。

此外 - 如果您需要查询是确定性的,请使用SELECT TOP N WITH TIES方法或在ORDER BY的{​​{1}}子句中添加主键或某种“uniquifier”查询。

SELECT TOP

结果:

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;

答案 1 :(得分:1)

我认为答案仍然是错误的,但非常接近。它仍然错过了最后一天 该月的最后一天凌晨12:00:00就是前一天的结束。 要包括完整的最后一天,它应该到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

答案 2 :(得分: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

一步一步为什么我这样做:

作为CTE的LastMonth所以我不必为了性能和可读性而重复过滤基础数据集。

最后三个值是通过不存在的链+存在来完成的。这些用于过滤掉lastMonth中的数据,以便只允许返回三个记录(通过三个连接完成)。

答案 3 :(得分: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