2012-02-01 92 views
1

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

请提供一个一步一步的答案,为什么你使用你正在使用的方法。

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

  1. 创建一个游标由客户名称通过CustomerTransaction表组迭代
  2. 创建内部查询获得客户的最后3个交易前一个月(使用选前3名),将其插入到一个临时表
  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 2012-02-01 03:04:17

+0

下一个你认为使用游标作为解决方案的一部分的时候,请你帮个忙,并踢自己 – 2012-02-01 04:20:18

回答

2

我自己更喜欢交叉应用&为了简单的顶级组合。

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

而且 - 如果你需要查询的是确定性的,要么使用SELECT TOP N WITH TIES方式或添加主键或某种形式的“唯一标志”到SELECT TOP查询ORDER BY条款。

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这样我就不必反复筛选基础数据集,无论是性能和可读性。

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

+0

披露:sqlfiddle.com是我的地盘 – 2012-02-01 03:11:46

+0

如果我增加一个交易具有相同日期的表格,它将作为计数一笔交易。因此,不是获得前3名,而是获得前4名(包括具有相同交易日期的一笔交易)。 '插入CustomerTransaction(客户名称,金额,TransactionDate)VALUES(“约翰”,100.0,“2011-12-29”)' – Wisp 2012-02-01 04:01:10

+0

这是真的,我认为交易日期基本上是时间戳,以重复的没有现实的可能性。 – 2012-02-01 04:24:59

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: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 
相关问题