SQL Server连续发票排除36个月后的差距

时间:2014-09-23 20:33:09

标签: sql sql-server

我正在努力解决使用公式来识别忠诚客户的问题,我希望能够提供一些见解。 忠诚客户标准如下:

  • 客户必须在36内至少开具4次发票 几个月,发票在以下时间范围内下降:
    • 第一张发票(A) - 这不一定是第一次发票 客户的发票,只是第一张发票 这种模式
    • 第二张发票(B) - 必须在1-12个月内发生 在发票A
    • 之后
    • 第三张发票(C) - 必须在13-24个月内发生 在发票A
    • 之后
    • 第四张发票(D) - 必须在25-36个月内发生 在发票A
    • 之后
  • 满足这些条件后,所有发票日期均大于 或等于A被视为忠诚的客户发票
    • 只有具有正子总数的发票才算作合格 发票(A,B,C或D),但所有发票应计算一次 客户符合资格标准

到目前为止,我对此很满意。这是我正在使用的查询(这很慢,但我不是经常运行它所以我并不特别关心速度):

;WITH 

T1 AS 
( 
SELECT
CUSTOMER_ID,
INVOICE_DATE,
DATEPART(YEAR, INVOICE_DATE)*12 + DATEPART(MONTH, INVOICE_DATE) AS YM
FROM INVOICE
WHERE Sub_Total > 0
),

T2 AS
(
SELECT DISTINCT 
A.CUSTOMER_ID,
A.INVOICE_DATE A_DATE
FROM T1 A
JOIN T1 B ON A.CUSTOMER_ID = B.CUSTOMER_ID AND (B.YM > A.YM AND B.YM <= (A.YM + 12))
JOIN T1 C ON A.CUSTOMER_ID = C.CUSTOMER_ID AND (C.YM > B.YM AND C.YM BETWEEN (A.YM + 13) AND (A.YM + 24))
JOIN T1 D ON A.CUSTOMER_ID = D.CUSTOMER_ID AND (D.YM > C.YM AND D.YM BETWEEN (A.YM + 25) AND (A.YM + 36))
)

SELECT DISTINCT 
I.CUSTOMER_ID,
C.CUSTOMER_NAME,
I.INVOICE_ID,
cast(i.Invoice_Date as Date) as Invoice_Date,
DATEPART(YEAR, I.INVOICE_DATE)*12 + DATEPART(MONTH, I.INVOICE_DATE) AS YM,
DATEPART(MONTH, I.INVOICE_DATE) AS Mo,
DATEPART(YEAR, I.INVOICE_DATE) AS Yr,
I.SUB_TOTAL
FROM INVOICE I
JOIN T2 ON T2.CUSTOMER_ID = I.CUSTOMER_ID AND I.INVOICE_DATE >= A_DATE
JOIN CUSTOMER C ON C.CUSTOMER_ID = I.CUSTOMER_ID
ORDER BY I.CUSTOMER_ID, INVOICE_DATE

然而,导致我被卡住的原因是另一个标准,即如果忠诚的客户在没有开具发票的情况下持续36个月,他们将不再被视为忠诚,并且不应计算36个月差距之后的任何发票。如果客户在36个月的差距之后再次完成上述(A,B,C和D)的4个合格发票,则将其视为一组新的忠诚发票。

示例:

+--------------------+--------------------+-----------------+
| Invoice Month/Year | Qualifying Invoice | Count as Loyal? |
+--------------------+--------------------+-----------------+
| 01/04              | N/A                | No              |
| 03/05              | A                  | Yes             |
| 09/05              | B                  | Yes             |
| 12/05              | N/A                | Yes             |
| 06/06              | C                  | Yes             |
| 04/07              | D                  | Yes             |
| 06/07              | N/A                | Yes             |
| 07/10              | N/A                | No              |
| 08/10              | N/A                | No              |
| 09/11              | A                  | Yes             |
| 10/11              | B                  | Yes             |
| 01/13              | C                  | Yes             |
| 04/14              | D                  | Yes             |
| 06/14              | N/A                | Yes             |
+--------------------+--------------------+-----------------+

如果我让这个太复杂,我道歉。最后,我希望能够深入了解如何在36个月之后排除所有发票,除了那些再次符合忠诚客户标准的发票。

1 个答案:

答案 0 :(得分:1)

这是一种使用CTE计算间隙的方法。如果你有SQL2012或更高版本,lag窗口函数会使这更简单。

祝你好运收集信息!

with x as (
  select
    invoice_id,
    customer_id,
    invoice_date,
    row_number() over (partition by customer_id order by invoice_date) rn
    -- SQL2012 has lag which is easier, can compute the gap directly (untested)
    -- datediff(month, lag(invoice_date, 1) over (
    --       partition by customer_id 
    --       order by invoice_date
    -- ), invoice_date) as gap
  from
    invoice
  where
    sub_total > 0
) select
  x1.*,
  datediff(month, x2.invoice_date, x1.invoice_date) gap
from
  x x1
    left join
  x x2
    on x1.customer_id = x2.customer_id and x1.rn = x2.rn + 1;

Example SQLFiddle