我需要获得上个月每位客户最近3笔交易的总金额。我们今天说的是2012/1/31。
请逐步解答您使用所用方法的原因。
例如,这是我想到的答案。这可能是错的。
所以我有一个包含以下列的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 :(得分: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