使用分区依据、分组依据和一起计数

using partition by, group by and count together

Blockquote Copy/Paste data:

productNumber   Account BuyDate SellDate    RelevantYYYYMM
27530   8605148 11/5/15 7:03 PM 11/11/15 2:02 PM    201511
27530   8582063 10/14/15 7:17 PM    10/16/15 1:48 PM    201510
27530   8566748 9/30/15 6:51 PM 10/13/15 2:09 PM    201510
101167  8622268 11/27/15 7:50 PM    11/27/15 8:35 PM    201511
101167  8622267 11/27/15 8:49 AM    11/27/15 11:02 AM   201511
101167  8622265 11/26/15 8:47 AM    11/26/15 11:14 AM   201511
101167  8622272 11/25/15 7:43 PM    11/25/15 8:40 PM    201511
102432  8611407 11/12/15 5:41 PM    11/25/15 11:50 AM   201511
102432  8600664 11/2/15 12:04 AM    11/4/15 12:56 PM    201511
102432  8573179 10/5/15 2:03 PM 10/7/15 3:47 PM 201510
127819  8581822 10/14/15 7:49 PM    10/18/15 10:46 AM   201510
127819  8572308 10/2/15 4:38 PM 10/4/15 2:28 PM 201510
127819  8571220 10/2/15 9:34 AM 10/2/15 4:25 PM 201510
141105  8612529 11/16/15 7:45 AM    11/16/15 3:06 PM    201511
141105  8612460 11/14/15 10:04 AM   11/14/15 12:48 PM   201511
141105  8608738 11/10/15 12:53 PM   11/10/15 3:19 PM    201511
141105  8603007 11/3/15 5:28 PM 11/9/15 3:54 PM 201511
141105  8595018 10/28/15 7:23 PM    11/2/15 2:09 PM 201511
141105  8562238 10/22/15 8:40 AM    10/27/15 5:11 PM    201510

我需要按 RelevantYYYYMM 计算 ProductNumber 组的数量(201512 表示 2015 年 12 月)。但是,逻辑应该是:

  1. ProductNumber 及其最近的 BuyDate 应该在那个 RelevantYYYYMM 之内。
  2. 与 ProductNumber 的最新 BuyDate 关联的上一个 BuyDate 应在 30 天范围内。示例:产品 27530 的最近购买日期是 2015 年 11 月 5 日。产品的上一个购买日期是 10/14/15,距 11.5.15 的 30 天内。
  3. 第三个购买日期应在第二个购买日期的 30 天范围内。示例:ProductNumber 27530 的第二个购买日期是 10/14/15,第三个购买日期是 9/30/15,在 10/14/15 的 30 天范围内。
  4. 应针对与该编号关联的每个 ProductNumber 和 RelevantYYYYMM 执行此验证。示例:对于 RelevantYYYYMM 201510(2015 年 10 月),ProductNumber 27530 不应出现在我的计数中,因为不满足 Stpes 1-3。解释:201510(2015 年 10 月)ProductNumber 27530 的最近日期是 10/14/2015。之前的 BuyDate 是 9/30/2015,在 10/14/2015 的 30 天范围内。但是,该 ProductNumber 在 9/30/2015 之前的 30 天范围内没有另一个 BuyDate。它无法验证第 3 步,因此从计数中删除。

代码:

--get all products and assign YYYYMM
drop table #firstbuy
declare @StartDate as date  = '01/01/2015'
declare @EndDate as date = '12/31/2015'

select ProductNumber, Account, BuyDate, SellDate,
CAST(DATEPART(yyyy, BuyDate) AS varchar(4))+ 
CAST(REPLICATE('0', 2-LEN(MONTH(BuyDate))) AS varchar(2)) +
CAST(DATEPART(MONTH, BuyDate) AS varchar(2)) AS RelevantYYYYMM
into #firstbuy
From products V
WHERE
V.BuyDate BETWEEN @StartDate AND @EndDate 
--select * from #firstbuy

--Rank by BuyDate desc.  Use ProductNumber and RelevantYYYYMM for partition     by
drop table #firstbuypart2
select * 
into #firstbuypart2
from (
select ProductNumber, Account, BuyDate, SellDate, RelevantYYYYMM,
                ROW_NUMBER() OVER (PARTITION BY ProductNumber,     RelevantYYYYMM ORDER BY BuyDate DESC) AS     getcount1                               
from #firstbuy
) a
--select * from #firstbuypart2 

--Grab records that has count = 1.  This will give you most recent BuyDate per RelevantYYYYMM
drop table #firstbuypart3
select ProductNumber, BuyDate, SellDate, RelevantYYYYMM 
into #firstbuypart3
from #firstbuypart2
where getcount1 = 1
Group BY ProductNumber, RelevantYYYYMM, BuyDate, SellDate,
order by ProductNumber
--select * from #firstbuypart3


--Not sure what logic to use to get only one specific row per ProductNumber and RelevantYYYYMM
drop table #firstbuypart4
select b.*, a.BuyDate as BuyDateA, a.SellDate as SellDateA,
CAST(DATEPART(yyyy, a.BuyDateA) AS varchar(4))+ 

CAST(REPLICATE('0', 2-LEN(MONTH(a.BuyDateA))) AS varchar(2)) +

CAST(DATEPART(MONTH, a.BuyDateA) AS varchar(2)) AS RelevantYYYYMM_A  
into #firstdischargepart4
From products a
JOIN #firstbuypart3 b on a.ProductNumber = b.ProductNumber
WHERE 
DATEDIFF(DAY,b.BuyDate,a.BuyDate) BETWEEN 0 AND 30
--select * from #firstbuypart4

我认为这可能是您需要的:

ATTENTION_1:您不应该使用特定于文化的日期时间格式!看这里:

ATTENTION_2:注意日期时间! BETWEEN @StartDate AND @EndDate 如果有时间,将不包括 @EndDate 的 BuyDates!

SET LANGUAGE ENGLISH;

DECLARE @tbl TABLE(productNumber INT,Account INT,BuyDate DATETIME,SellDate DATETIME);
INSERT INTO @tbl VALUES
 (27530,8605148,'11/5/15 7:03 PM','11/11/15 2:02 PM')
,(27530,8582063,'10/14/15 7:17 PM','10/16/15 1:48 PM')
,(27530,8566748,'9/30/15 6:51 PM','10/13/15 2:09 PM')
,(101167,8622268,'11/27/15 7:50 PM','11/27/15 8:35 PM')
,(101167,8622267,'11/27/15 8:49 AM','11/27/15 11:02 AM')
,(101167,8622265,'11/26/15 8:47 AM','11/26/15 11:14 AM')
,(101167,8622272,'11/25/15 7:43 PM','11/25/15 8:40 PM')
,(102432,8611407,'11/12/15 5:41 PM','11/25/15 11:50 AM')
,(102432,8600664,'11/2/15 12:04 AM','11/4/15 12:56 PM')
,(102432,8573179,'10/5/15 2:03 PM','10/7/15 3:47 PM')
,(127819,8581822,'10/14/15 7:49 PM','10/18/15 10:46 AM')
,(127819,8572308,'10/2/15 4:38 PM','10/4/15 2:28 PM')
,(127819,8571220,'10/2/15 9:34 AM','10/2/15 4:25 PM')
,(141105,8612529,'11/16/15 7:45 AM','11/16/15 3:06 PM')
,(141105,8612460,'11/14/15 10:04 AM','11/14/15 12:48 PM')
,(141105,8608738,'11/10/15 12:53 PM','11/10/15 3:19 PM')
,(141105,8603007,'11/3/15 5:28 PM','11/9/15 3:54 PM')
,(141105,8595018,'10/28/15 7:23 PM','11/2/15 2:09 PM')
,(141105,8562238,'10/22/15 8:40 AM','10/27/15 5:11 PM');

declare @StartDate as date  = '01/01/2015';
declare @EndDate as date = '12/31/2015';

WITH Extended AS
(
    SELECT ProductNumber
          ,Account
          ,BuyDate
          ,SellDate
          ,CAST(YEAR(BuyDate) AS VARCHAR(4))+ REPLACE(STR(MONTH(BuyDate),2),' ','0') AS RelevantYYYYMM
          ,ROW_NUMBER() OVER(PARTITION BY ProductNumber ORDER BY productNumber,BuyDate DESC) AS RowInx
          ,COUNT(BuyDate) OVER(PARTITION BY ProductNumber) AS CountBuyDates
    FROM @tbl
    WHERE BuyDate BETWEEN @StartDate AND @EndDate --ATTENTION!!! Be aware of DateTime! this will NOT include BuyDates from @EndDate, if there is a time!
)
,DayDiffs AS
(
    SELECT *
          ,DATEDIFF(DAY,ext.BuyDate
                      ,(SELECT innerExt.BuyDate FROM Extended AS innerExt WHERE innerExt.productNumber=ext.productNumber AND innerExt.RowInx=ext.RowInx-1)) AS IntervalRecentToSecond 
          ,DATEDIFF(DAY,(SELECT innerExt.BuyDate FROM Extended AS innerExt WHERE innerExt.productNumber=ext.productNumber AND innerExt.RowInx=ext.RowInx-1)
                       ,(SELECT innerExt.BuyDate FROM Extended AS innerExt WHERE innerExt.productNumber=ext.productNumber AND innerExt.RowInx=ext.RowInx-2)) AS IntervalSecondToThird
    FROM Extended AS ext
    WHERE ext.CountBuyDates>=3 --min three
      AND ext.RowInx=3 --this is the relevant row
)
SELECT productNumber 
      ,Account 
      ,RelevantYYYYMM AS Relev
      ,IntervalRecentToSecond AS Diff1To2
      ,IntervalSecondToThird AS Diff2To3
FROM DayDiffs

结果将是:

productNumber   Account Relev   Diff1To2    Diff2To3
27530           8566748 201509  14          22
101167          8622265 201511  1           0
102432          8573179 201510  28          10
127819          8571220 201510  0           12
141105          8608738 201511  4           2

我必须承认,我并没有真正理解您的 "RelevantYYYYMM" 分组应该如何工作。但我认为,您自己可以 fiddle 做到这一点...如果不能:请回来做一个简短的解释。