1

我有记录某些物品何时被发送或退回到特定位置的表格,我想计算出每次退回特定物品的时间间隔。

样本数据:

Item   ReturnDate:
Item1, 20120101
Item1, 20120201
Item1, 20120301
Item2, 20120401
Item2, 20120601

所以在这种情况下,我们可以看到第一次退回第 1 项之前有一个月的差距,在第二次退回之前还有一个月。第 2 项在 2 个月后回来了。

我的出发点是:

Select r1.Item, r1.ReturnDate, r2.Item, r2.ReturnDate, DateDiff(m, r1.ReturnDate, r2.ReturnDate)
from Returns r1
inner join Returns r2 on r2.VehicleNo = r1.VehicleNo

但是,在此示例中,每个项目都与它已返回的每个其他实例进行比较 - 而不仅仅是下一个。所以我需要限制这个查询,所以它只会比较相邻的返回。

一种解决方案是用计数(该项目被退回的次数)标记每个退货:

Item   ReturnDate, ReturnNo:
Item1, 20120101,   1
Item1, 20120201,   2
Item1, 20120301,   3
Item2, 20120401,   1
Item2, 20120601,   2

这将使我能够使用以下 T-SQL(或类似的):

Select r1.Item, r1.ReturnDate, r2.Item, r2.ReturnDate, DateDiff(m, r1.ReturnDate, r2.ReturnDate)
from Returns r1
inner join Returns r2 on r2.VehicleNo = r1.VehicleNo 
and (r1.ReturnNo + 1 = r2.ReturnNo)

我的第一个问题是这是否是一种明智/最佳的方法,或者是否有更好的方法?

其次,计算 ReturnNo 的最简单/最巧妙的方法是什么?

4

3 回答 3

4

如果您使用的是 SQL Server 2005+,请使用 ROW_NUMBER() 来完成您想要的操作:

WITH RankedReturn AS
(
  SELECT Item, ReturnDate, 
    ROW_NUMBER() OVER (PARTITION BY Item ORDER BY ReturnDate DESC) AS ReturnNo
  FROM Returns
)
SELECT * FROM RankedReturn

显然,现在您有了 CTE,您可以将所需的任何内容放入外部 SELECT 中。我会为此使用 OUTER APPLY:

WITH RankedReturn AS
(
  SELECT Item, ReturnDate, 
    ROW_NUMBER() OVER (PARTITION BY Item ORDER BY ReturnDate DESC) AS ReturnNo
  FROM Returns
)
SELECT rOuter.Item, rOuter.ReturnDate, DATEDIFF(month, prev.PrevDate, ReturnDate) AS Months
FROM RankedReturn rOuter
OUTER APPLY 
  (
    SELECT ReturnDate AS PrevDate 
    FROM RankedReturn rInner 
    WHERE rOuter.Item = rInner.Item AND rOuter.ReturnNo = rInner.ReturnNo - 1
  ) prev

糟糕,SQL Fiddle 在这里

编辑因为月差计算是倒退的;现在修复

于 2012-06-12T14:35:39.107 回答
3

计算 ReturnNo 的最简单方法是使用OVER

SELECT [Item], [ReturnDate], 
    ROW_NUMBER() OVER (PARTITION BY [Item] ORDER BY [ReturnDate]) AS ReturnNumber
FROM Returns

http://sqlfiddle.com/#!3/e18ad/1/0

您还可以尝试使用计算运行总计的技术来计算两行之间的差异。

于 2012-06-12T14:35:22.617 回答
2

我会这样做:

select  itemNo,
        dt,
        DATEDIFF(day, previousDt, dt) as daysSince
from    (select itemNo, 
                dt,
                (select top 1 dt from testTable where itemNo = outerTbl.itemNo and dt < outerTbl.dt order by dt desc) as previousDt
        from    testTable as outerTbl
        ) as x

...这里有一些设置代码供其他人测试解决方案

create table testTable(
itemNo nvarchar(20),
dt datetime)
go

insert into testTable values('Item1', '2012-01-01');
insert into testTable values('Item1', '2012-02-01');
insert into testTable values('Item1', '2012-03-01');
insert into testTable values('Item2', '2012-04-01');
insert into testTable values('Item2', '2012-05-01');
go
于 2012-06-12T14:38:15.910 回答