计算时间范围内返回项目的数量

时间:2017-07-25 13:39:34

标签: sql sql-server tsql

上下文

对于返回的每件商品,我们需要知道“此”商品在不同时间段内退回的时间:30,60,90,120,180,365天。

项目基于其序列号(Itm_Item_Serial)是唯一的。

样本数据:

使用创建脚本完成示例,并预期结果为here *。

CREATE TABLE ItemReturn
(
     [Itm_Id] int, 
     [Itm_Item_Serial] int, 
     [Itm_CDate] datetime
);

INSERT INTO ItemReturn ([Itm_Id], [Itm_Item_Serial], [Itm_CDate])
VALUES       
    (1, 1, '2016-10-02 02:00:00'),
    (2, 1, '2016-09-03 02:00:00'),
    (3, 1, '2016-11-03 01:00:00')   
;

预期结果:对于Itm_Item_Serial = 1

Itm_Id    30d    60d    90d    120d    180d    365d
1          0      0      0      0       0        0
2          1      0      0      0       0        0
3          1      1      0      0       0        0

0或如果此时间范围内没有返回则为null。

它是如何工作的:对于Itm_Item_Serial = 1

[Itm_Id]  [Itm_Item_Serial] [Itm_CDate] 
1,         1,               '2016-10-02 02:00:00'
2,         1,               '2016-09-03 02:00:00'
3,         1,               '2016-11-03 01:00:00'
  • 对于[Itm_Id] = 1,前一次返回0。
  • 对于[Itm_Id] = 2,先前有1次返回
    • on'2016-10-02'。 datediff = 29.所以在“0-30天”的时间范围内有一个回报。
  • 对于[Itm_Id] = 3,前面有2个返回。
    • on'2016-09-03'。 datediff = 60.所以在“30-60天”的时间范围内有一次回归。
    • on'2016-10-02'。 datediff = 31.所以在“30-60天”的时间范围内有一次回归。

*:rextester数据样本和有序数据样本。

3 个答案:

答案 0 :(得分:1)

SQL小提琴:http://sqlfiddle.com/#!6/00460/4

不会为您提供您提供的结果,但会提供不同日期失误的计数

; with data_CTE as (
    select
        m1.Itm_CDate
        , DATEDIFF(day, m1.Itm_CDate, m2.Itm_CDate) DayDiff
        , m1.Itm_id
        , m1.Itm_Item_Serial
    from ItemReturn m1
        left outer join ItemReturn m2
            on m1.Itm_Item_Serial = m2.Itm_Item_Serial
    where m1.Itm_CDate < m2.Itm_CDate
        and m1.Itm_CDate > DATEADD(day, -30, m2.Itm_CDate)
), aggr_CTE as (
    select 
        Itm_Id, Itm_Item_Serial
        , case 
            when DayDiff < 30 then '30d'
            when DayDiff < 60 then '60d'
            when DayDiff < 90 then '90d'
            when DayDiff < 120 then '120d'
            when DayDiff < 180 then '180d'
            else '365d'
        end DayLapse
    from data_CTE
)select 
    Itm_id, [30d], [60d], [90d], [120d], [180d], [365d]
from (
    select Itm_id, Itm_Item_Serial, DayLapse
    from aggr_CTE
) src PIVOT (
    count(Itm_Item_Serial)
    for DayLapse in ([30d], [60d], [90d], [120d], [180d], [365d])
) as PivotTable

data_CTE结果(输出):

Itm_CDate               DayDiff     Itm_id      Itm_Item_Serial
----------------------- ----------- ----------- ---------------
2016-09-03 02:00:00.000 29          2           1
2016-09-03 02:00:00.000 29          3           1
2016-09-03 02:00:00.000 29          5           2
2016-09-03 02:00:00.000 29          13          6
2016-08-05 02:00:00.000 29          15          6
2016-08-04 02:00:00.000 1           14          6

更新时间:2017-07-26

查询的最终版本

; with data_CTE as ( 
     SELECT 
     Itm_Id 
     , Itm_Item_Serial 
     , ROW_NUMBER() over (Partition By Itm_Item_Serial order by Itm_Item_Serial) Itm_Item_RowNum 
     , Itm_CDate 
     FROM [ItemReturn] ir1 
 ), date_CTE as (
    select 
        d2.Itm_Id
        , d1.Itm_Item_Serial
        , DATEDIFF(day, d1.Itm_CDate, d2.Itm_CDate) DayDiff
     from data_CTE d1, data_CTE d2
     where d1.Itm_Item_Serial = d2.Itm_Item_Serial
        and DATEDIFF(day, d1.Itm_CDate, d2.Itm_CDate) >= 0
), aggr_CTE as (
    select 
        Itm_Id, Itm_Item_Serial
        , case 
            when DayDiff <= 0 then '0d'
            when DayDiff <= 30 then '30d'
            when DayDiff <= 60 then '60d'
            when DayDiff <= 90 then '90d'
            when DayDiff <= 120 then '120d'
            when DayDiff <= 180 then '180d'
            else '365d'
        end DayLapse
    from date_CTE
)select 
    Itm_id, [30d], [60d], [90d], [120d], [180d], [365d]
from (
    select Itm_id, Itm_Item_Serial, DayLapse
    from aggr_CTE
) src PIVOT (
    count(Itm_Item_Serial)
    for DayLapse in ([0d], [30d], [60d], [90d], [120d], [180d], [365d])
) as PivotTable

答案 1 :(得分:1)

您可以查询如下:

Select * from (
    Select Itm_id, Itm_Item_Serial, case when datediff(day, Itm_CDate, getdate()) between  0 and 30 then '30'
               when datediff(day, Itm_CDate, getdate()) between 30 and 60 then '60'
               when datediff(day, Itm_CDate, getdate()) between 60 and 90 then '90'
               when datediff(day, Itm_CDate, getdate()) between 90 and 120 then '120'
               when datediff(day, Itm_CDate, getdate()) between 120 and 180 then '180'
               when datediff(day, Itm_CDate, getdate()) between 180 and 360 then '365' 
                Else 0 End as test              
             from ItemReturn
) a
pivot (count(test) for test in ([30],[60],[90],[120],[180],[365])) p

如果您的差异日期介于下一个日期之间,那么您可能需要使用以下潜在客户:

;With cte as (
    Select *, NextDate = lead(itm_cDate) over(partition by Itm_Item_Serial order by Itm_id) 
        from ItemReturn
    ), cte2 as (
    Select Itm_id, Itm_Item_Serial, case when datediff(day, Itm_CDate, NextDate) between  0 and 30 then '30'
                when datediff(day, Itm_CDate, NextDate) between 30 and 60 then '60'
                when datediff(day, Itm_CDate, NextDate) between 60 and 90 then '90'
                when datediff(day, Itm_CDate, NextDate) between 90 and 120 then '120'
                when datediff(day, Itm_CDate, NextDate) between 120 and 180 then '180'
                when datediff(day, Itm_CDate, NextDate) between 180 and 360 then '365' 
                Else 0 End as test              
                from cte
    )
    Select * from cte2 
    pivot (count(test) for test in ([30],[60],[90],[120],[180],[365])) p

Demo此处

答案 2 :(得分:1)

不是最终的答案,而是光滑的方式来获得差异

with cte as 
select [Itm_Id], [Itm_Item_Serial], [Itm_CDate] 
     , row_number() over (partition by [Itm_Item_Serial] order by [Itm_CDate]) as rn
from ItemReturn;
select t1.*
     , datediff(dd, t1.[Itm_CDate], t2.[Itm_CDate] desc) as diff 
     , t2.[Itm_Id], t2.[Itm_CDate]
 from cte t1 
 join cte t2 
   on t1.[Itm_Item_Serial] = t2.[Itm_Item_Serial] 
  and t1.rn = 1 
  and t2.rn <> 1
order by t1.[Itm_Item_Serial], t1.rn