使用分区依据、分组依据和一起计数
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 月)。但是,逻辑应该是:
- ProductNumber 及其最近的 BuyDate 应该在那个 RelevantYYYYMM 之内。
- 与 ProductNumber 的最新 BuyDate 关联的上一个 BuyDate 应在 30 天范围内。示例:产品 27530 的最近购买日期是 2015 年 11 月 5 日。产品的上一个购买日期是 10/14/15,距 11.5.15 的 30 天内。
- 第三个购买日期应在第二个购买日期的 30 天范围内。示例:ProductNumber 27530 的第二个购买日期是 10/14/15,第三个购买日期是 9/30/15,在 10/14/15 的 30 天范围内。
- 应针对与该编号关联的每个 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 做到这一点...如果不能:请回来做一个简短的解释。
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 月)。但是,逻辑应该是:
- ProductNumber 及其最近的 BuyDate 应该在那个 RelevantYYYYMM 之内。
- 与 ProductNumber 的最新 BuyDate 关联的上一个 BuyDate 应在 30 天范围内。示例:产品 27530 的最近购买日期是 2015 年 11 月 5 日。产品的上一个购买日期是 10/14/15,距 11.5.15 的 30 天内。
- 第三个购买日期应在第二个购买日期的 30 天范围内。示例:ProductNumber 27530 的第二个购买日期是 10/14/15,第三个购买日期是 9/30/15,在 10/14/15 的 30 天范围内。
- 应针对与该编号关联的每个 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 做到这一点...如果不能:请回来做一个简短的解释。