让所有客户进行有限的交易

时间:2016-03-20 16:39:07

标签: sql sql-server sql-server-2008 sql-server-2012

我必须连续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

2 个答案:

答案 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),或者精确计算内联。

  1. 第一次CTE获取的交易数据包含该组的行号和开始月份编号(客户和付款系列)。

  2. 对于每个类别,少量和20K(大额),我从之前的CTE中选择了基于金额的过滤。

  3. 对于每个系列,应用计数标准(6小额付款,然后是3大付款)。

  4. 根据客户和日期加入小额和大额付款(组月份是最小的组月份 - 1)。

  5. 最终查询如下:

    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