我必须连续6个月提取所有每月交易少于5000的客户名称,然后在第7个月进行3次交易,每次交易20,000次。
客户的所有交易将存储在不同的行中。
示例:考虑客户A,客户的信息将按如下方式存储:
Name | TransactionDate | Amount
1. CustomerA | 27-08-2015 | 4500
2. CustomerA | 27-09-2015 | 4500
3. CustomerA | 27-10-2015 | 4500
4. CustomerA | 27-11-2015 | 4500
5. CustomerA | 27-12-2015 | 4500
6. CustomerA | 27-01-2016 | 4500
7. CustomerA | 27-02-2016 | 20000
8. CustomerA | 27-02-2016 | 20000
9. CustomerA | 27-02-2016 | 20000
答案 0 :(得分:0)
在你指定SQL
味道之前,我认为我为T-SQL
提供了灵活而体面的解决方案:
1)为了有更简单的查询,我已经定义为持久列来存储月号是一种方便的方法:
create table CustomerTransaction
(
CustomerName VARCHAR(20),
TransactionDate DATE,
Amount NUMERIC(18, 2),
MonthNo AS DATEPART(yyyy, TransactionDate) * 12 + DATEPART(mm, TransactionDate) - 1 PERSISTED
)
如果无法使用,您可以使用员工日期算术(DATEDIFF
),或者精确计算内联。
第一次CTE获取的交易数据包含该组的行号和开始月份编号(客户和付款系列)。
对于每个类别,少量和20K(大额),我从之前的CTE中选择了基于金额的过滤。
对于每个系列,应用计数标准(6小额付款,然后是3大付款)。
根据客户和日期加入小额和大额付款(组月份是最小的组月份 - 1)。
最终查询如下:
declare @SmallAmountsLen INT = 6;
declare @BigAmountsLen INT = 3;
declare @SmallAmountThreshold NUMERIC(18, 2) = 5000
declare @BigAmount NUMERIC(18, 2) = 20000
;with AmountCte AS (
SELECT CustomerName, TransactionDate, Amount, MonthNo, ROW_NUMBER() OVER (PARTITION BY CustomerName ORDER BY TransactionDate) AS RowNo,
MonthNo - ROW_NUMBER() OVER (PARTITION BY CustomerName ORDER BY TransactionDate) AS GroupMonthNo
FROM CustomerTransaction
),
SmallAmountCte AS (
SELECT *
FROM AmountCte
WHERE Amount < @SmallAmountThreshold
),
BigAmountCte AS (
SELECT *
FROM AmountCte
WHERE Amount = @BigAmount
),
SmallGroupCte AS (
select CustomerName, GroupMonthNo
from SmallAmountCte
group by CustomerName, GroupMonthNo
having count(1) = @SmallAmountsLen
),
BigGroupCte AS (
select CustomerName, MonthNo
from BigAmountCte
group by CustomerName, MonthNo
having count(1) = @BigAmountsLen
)
select S.*, B.*
from SmallGroupCte S
join BigGroupCte B on B.CustomerName = S.CustomerName
where B.MonthNo = S.GroupMonthNo + @SmallAmountsLen + 1
[编辑]查询,无需计算列
declare @SmallAmountsLen INT = 6;
declare @BigAmountsLen INT = 3;
declare @SmallAmountThreshold NUMERIC(18, 2) = 5000
declare @BigAmount NUMERIC(18, 2) = 20000
;with AmountCte AS (
SELECT CustomerName, TransactionDate, Amount, DATEPART(yyyy, TransactionDate) * 12 + DATEPART(mm, TransactionDate) - 1 AS MonthNo,
ROW_NUMBER() OVER (PARTITION BY CustomerName ORDER BY TransactionDate) AS RowNo,
DATEPART(yyyy, TransactionDate) * 12 + DATEPART(mm, TransactionDate) - 1 - ROW_NUMBER() OVER (PARTITION BY CustomerName ORDER BY TransactionDate) AS GroupMonthNo
FROM CustomerTransaction
),
SmallAmountCte AS (
SELECT *
FROM AmountCte
WHERE Amount < @SmallAmountThreshold
),
BigAmountCte AS (
SELECT *
FROM AmountCte
WHERE Amount = @BigAmount
),
SmallGroupCte AS (
select CustomerName, GroupMonthNo
from SmallAmountCte
group by CustomerName, GroupMonthNo
having count(1) = @SmallAmountsLen
),
BigGroupCte AS (
select CustomerName, MonthNo
from BigAmountCte
group by CustomerName, MonthNo
having count(1) = @BigAmountsLen
)
select S.*, B.*
from SmallGroupCte S
join BigGroupCte B on B.CustomerName = S.CustomerName
where B.MonthNo = S.GroupMonthNo + @SmallAmountsLen + 1
答案 1 :(得分:0)
这是一个更简单的查询来获得结果,我想要的是:
WITH CTE
AS
(
SELECT * FROM
(
SELECT DENSE_RANK() OVER (PARTITION BY Name ORDER BY DATEPART(MONTH,TransactionDate)) AS SrNo,
Name,Amount,DatePart(Month,TransactionDate) AS MonthNo,TransactionDate FROM TransactionTable) AS A
WHERE
(Amount <= 5000 AND SrNo < 7) OR (Amount = 20000 AND SrNo = 7)
)
SELECT A.Name AS Account_Number,A.Transaction_Date FROM
(
SELECT Name,Amount,COUNT(SrNo) As Sr,MAX(TransactionDate) AS Transaction_Date FROM CTE
WHERE SrNo = 7 AND Amount = 20000
GROUP BY Name,Amount
HAVING COUNT(srNo) = 3) AS A
INNER JOIN
(
SELECT Name,COUNT(SrNo) AS Ss FROM CTE
WHERE SrNo < 7 AND Amount <= 5000
GROUP BY Name
HAVING COUNT(srNo) = 6) AS B
ON A.Name = B.Name