Sql server SQL-筛选日期X与上一个日期相隔的天数
我有一张包含订单的桌子。我想为特定客户选择相隔一定天数的订单。例如,在下表中,我想选择CustomerID=10的所有订单,这些订单与前一个实例至少相隔30天。起始点为第一次发生(本数据中为2014年5月7日) 我想选择OrderID(1,6,8),因为它们彼此相隔30天,并且都来自Sql server SQL-筛选日期X与上一个日期相隔的天数,sql-server,tsql,sql-server-2012,Sql Server,Tsql,Sql Server 2012,我有一张包含订单的桌子。我想为特定客户选择相隔一定天数的订单。例如,在下表中,我想选择CustomerID=10的所有订单,这些订单与前一个实例至少相隔30天。起始点为第一次发生(本数据中为2014年5月7日) 我想选择OrderID(1,6,8),因为它们彼此相隔30天,并且都来自CustomerID=10。订单ID 2和7将不包括在内,因为它们在该客户上一次订单的30天内 让我困惑的是如何将“检查点”设置为最后一个有效日期。下面是一个小的“伪”SQL 更新 一种稍微可靠一点的方法是使用一张临
CustomerID=10
。订单ID 2和7将不包括在内,因为它们在该客户上一次订单的30天内
让我困惑的是如何将“检查点”设置为最后一个有效日期。下面是一个小的“伪”SQL
更新 一种稍微可靠一点的方法是使用一张临时桌子。但是原始表
tbl
可以保持不变。请看这里:
CREATE TABLE #tmp (id int); -- set-up temp table
INSERT INTO #tmp VALUES (1); -- plant "seed": first oid
WHILE (@@ROWCOUNT>0)
INSERT INTO #tmp (id)
SELECT TOP 1 OrderId FROM tbl
WHERE OrderId>0 AND CustomerId=10
AND OrderDate>(SELECT max(OrderDate)+30 FROM tbl INNER JOIN #tmp ON id=OrderId)
ORDER BY OrderDate;
-- now list all found entries of tbl:
SELECT * FROM tbl WHERE EXISTS (SELECT 1 FROM #tmp WHERE id=OrderId)
您可以将SQL Server 2012中提供的LAG()
函数与公共表表达式一起使用。您计算客户当前订单与客户上一订单之间的天数,然后使用过滤器=30
with cte as
(select OrderId
,CustomerId
,datediff(d
,lag(orderdate) over (partition by CustomerId order by OrderDate)
,OrderDate) DaysSinceLastOrder
from Orders)
select OrderId, CustomerId, DaysSinceLastOrder
from cte
where DaysSinceLastOrder >= 30 or DaysSinceLastOrder is null
结果:
OrderId CustomerId DaysSinceLastOrder
1 10 NULL
6 10 70
3 11 NULL
4 11 31
5 11 32
(请注意,1970-01-01是任意选择的,您可以选择任何日期)我来到这里,看到
@SveinFidjestøl
已经发布了答案,但经过长期尝试后,我无法控制自己:
借助于LAG
和LEAD
我们可以在同一列之间进行比较
根据您的Q,您正在查找1,6,8
。也许这会有帮助
SQL SERVER 2012及其后版本
declare @temp table
(orderid int,
customerid int,
orderDate date
);
insert into @temp values (1, 10, '07/05/2014')
insert into @temp values (2, 10, '07/15/2014')
insert into @temp values (3, 11, '07/20/2014')
insert into @temp values (4, 11, '08/20/2014')
insert into @temp values (5, 11, '09/21/2014')
insert into @temp values (6, 10, '09/23/2014')
insert into @temp values (7, 10, '10/15/2014')
insert into @temp values (8, 10, '10/30/2014');
with cte as
(SELECT orderid,customerid,orderDate,
LAG(orderDate) OVER (ORDER BY orderid ) PreviousValue,
LEAD(orderDate) OVER (ORDER BY orderid) NextValue,
rownum = ROW_NUMBER() OVER (ORDER BY orderid)
FROM @temp
WHERE customerid = 10)
select orderid,customerid,orderDate from cte
where DATEDIFF ( day , PreviousValue , orderDate) > 30
or PreviousValue is null or NextValue is null
WITH CTE AS (
SELECT
rownum = ROW_NUMBER() OVER (ORDER BY p.orderid),
p.orderid,
p.customerid,
p.orderDate
FROM @temp p
where p.customerid = 10)
SELECT CTE.orderid,CTE.customerid,CTE.orderDate,
prev.orderDate PreviousValue,
nex.orderDate NextValue
FROM CTE
LEFT JOIN CTE prev ON prev.rownum = CTE.rownum - 1
LEFT JOIN CTE nex ON nex.rownum = CTE.rownum + 1
where CTE.customerid = 10
and
DATEDIFF ( day , prev.orderDate , CTE.orderDate) > 30
or prev.orderDate is null or nex.orderDate is null
GO
SQL SERVER 2005及以后版本
declare @temp table
(orderid int,
customerid int,
orderDate date
);
insert into @temp values (1, 10, '07/05/2014')
insert into @temp values (2, 10, '07/15/2014')
insert into @temp values (3, 11, '07/20/2014')
insert into @temp values (4, 11, '08/20/2014')
insert into @temp values (5, 11, '09/21/2014')
insert into @temp values (6, 10, '09/23/2014')
insert into @temp values (7, 10, '10/15/2014')
insert into @temp values (8, 10, '10/30/2014');
with cte as
(SELECT orderid,customerid,orderDate,
LAG(orderDate) OVER (ORDER BY orderid ) PreviousValue,
LEAD(orderDate) OVER (ORDER BY orderid) NextValue,
rownum = ROW_NUMBER() OVER (ORDER BY orderid)
FROM @temp
WHERE customerid = 10)
select orderid,customerid,orderDate from cte
where DATEDIFF ( day , PreviousValue , orderDate) > 30
or PreviousValue is null or NextValue is null
WITH CTE AS (
SELECT
rownum = ROW_NUMBER() OVER (ORDER BY p.orderid),
p.orderid,
p.customerid,
p.orderDate
FROM @temp p
where p.customerid = 10)
SELECT CTE.orderid,CTE.customerid,CTE.orderDate,
prev.orderDate PreviousValue,
nex.orderDate NextValue
FROM CTE
LEFT JOIN CTE prev ON prev.rownum = CTE.rownum - 1
LEFT JOIN CTE nex ON nex.rownum = CTE.rownum + 1
where CTE.customerid = 10
and
DATEDIFF ( day , prev.orderDate , CTE.orderDate) > 30
or prev.orderDate is null or nex.orderDate is null
GO
@tinka展示了如何使用CTE来实现这一点,而新的窗口函数(2012年及以后)可能是最好的答案。假设您没有非常大的数据集,还可以选择使用递归CTE 例如:
declare @customerid int = 10;
declare @temp table
(orderid int,
customerid int,
orderDate date
);
insert into @temp values (1, 10, '07/05/2014')
insert into @temp values (2, 10, '07/15/2014')
insert into @temp values (3, 11, '07/20/2014')
insert into @temp values (4, 11, '08/20/2014')
insert into @temp values (5, 11, '09/21/2014')
insert into @temp values (6, 10, '09/23/2014')
insert into @temp values (7, 10, '10/15/2014')
insert into @temp values (8, 10, '10/30/2014');
with datefilter AS
(
SELECT row_number() OVER(PARTITION BY CustomerId ORDER BY OrderDate) as RowId,
OrderId,
CustomerId,
OrderDate,
DATEADD(day, 30, OrderDate) as FilterDate
from @temp
WHERE CustomerId = @customerid
)
, firstdate as
(
SELECT RowId, OrderId, CustomerId, OrderDate, FilterDate
FROM datefilter
WHERE rowId = 1
union all
SELECT datefilter.RowId, datefilter.OrderId, datefilter.CustomerId,
datefilter.OrderDate, datefilter.FilterDate
FROM datefilter
join firstdate
on datefilter.CustomerId = firstdate.CustomerId
and datefilter.OrderDate > firstdate.FilterDate
WHERE NOT EXISTS
(
SELECT 1 FROM datefilter betweens
WHERE betweens.CustomerId = firstdate.CustomerId
AND betweens.orderdate > firstdate.FilterDate
AND datefilter.orderdate > betweens.orderdate
)
)
SELECT * FROM firstdate
您使用的是什么版本的SQL Server?您如何知道2014-07-05是客户10的“最后有效订单日期”?具体来说,是什么使它成为更大数据集中的最后一个有效顺序?我使用的是SQL Server 2012。假设这是完整的数据集,2014-07-05是第一个条目。因此,您希望选择
CustomerID=10
的所有内容,以及日期介于第一个日期和之后30天之间的所有内容?@Chase-第一次出现在第一个日期后30天,然后第一次出现在该日期后30天,等等。。。