忽略日期范围

时间:2017-11-13 20:10:32

标签: sql-server tsql

我有以下数据:

CREATE TABLE SampleData
(
    orderid int,
    [name] nvarchar(1),
    [date] date
);
INSERT INTO SampleData
VALUES
(1, 'a', '2017-01-01'),
(2, 'a', '2017-01-05'),
(3, 'a', '2017-02-01'),
(4, 'a', '2017-04-01'),
(5, 'a', '2017-10-01'),
(6, 'b', '2017-04-01');

我需要根据以下规则检索每个新订单:

  • 姓名的第一个日期是'当前订单'该名称
  • 与当前订单名称相同但订单少于3个月的订单'被视为相同的顺序,需要忽略
  • 与当前' 3个月或更长时间的差异订单被视为新订单,现在是'当前订单' (在SampleData中,orderid 1和4需要比较而不是3和4,因为3不是当前的顺序)
  • 如果名称和日期相同,则orderid最低的行是上级订单

因此,对于样本数据,我需要以下结果:

id name, date
1  a     2017-01-01
4  a     2017-04-01
5  a     2017-10-01
6  b     2017-04-01

我尝试了几种方法,但没有成功。关于如何实现这一目标的任何想法?

2 个答案:

答案 0 :(得分:0)

以下是一个快速修复解决方案,如果您的代码超出所提供的示例数据,则可以构建该解决方案。我会事先声明这不是最漂亮的解决方案,但它确实会返回您所指示的结果集。

如果有的话,您可能需要考虑查看T-SQL窗口函数以及分析函数。我会建议他们不能很好地适应所有数据类型。

我使用下面的解决方案的目标是按名称和按日期字段排序时对行进行排名。因此,您的订单ID与您的订单类似,但排名特定于下订单的客户。

我会尽力回答任何问题:

if object_id('tempdb..#tmp_SampleData','u') is not null
    drop table #tmp_SampleData

CREATE TABLE #tmp_SampleData
(
    orderid int,
    [name] nvarchar(1),
    [date] date
);
INSERT INTO #tmp_SampleData
VALUES
(1, 'a', '2017-01-01'),
(2, 'a', '2017-01-05'),
(3, 'a', '2017-02-01'),
(4, 'a', '2017-04-01'),
(5, 'a', '2017-10-01'),
(6, 'b', '2017-04-01');

if object_id('tempdb..#tmp_iter','u') is not null
    drop table #tmp_iter 

select 
 orderid
,name
,date
,rank() over (partition by name order by date) [Rank] 
,lag(orderid,1,0) over (partition by name order by date) [LagRank]
--,rank() over (partition by name order by date desc) [ReverseRank]
into #tmp_Iter 
from #tmp_SampleData

if object_id('tempdb..#tmp_final','u') is not null
    drop table #tmp_final 


select 
 i.orderid
,i.name
,i.date
,datediff(month,i.date,i2.date) [MonthsPassed]
into #tmp_final 
from #tmp_Iter i
    left join #tmp_Iter i2 
        on i.Rank = i2.LagRank

select * 
from #tmp_final 
where 1=1
and MonthsPassed > 3 
or MonthsPassed = 0 
or MonthsPassed < 0 
or MonthsPassed is null 

答案 1 :(得分:0)

@ SQLUser44,感谢您的输入。不幸的是你的代码无效。下表的结果应该是orderid的1,6,7,8和9.你的结果是1,2,3,5,6,7,8和9。

INSERT INTO #tmp_SampleData
VALUES
(1,'a','2017-01-01'),
(2,'a','2017-01-08'),
(3,'a','2017-05-01'),
(4,'a','2017-01-05'),
(5,'a','2017-02-01'),
(6,'b','2017-01-01'),
(7,'b','2017-09-01'),
(8,'c','2017-10-01'),
(9,'a','2017-04-01');

我提出了以下有效的方法,但我认为它会缺乏性能......

if object_id('tempdb..#tmp_SampleData','u') is not null
drop table #tmp_SampleData

CREATE TABLE #tmp_SampleData
(
    orderid int,
    [name] nvarchar(1),
    [date] date
);
INSERT INTO #tmp_SampleData
VALUES
(1,'a','2017-01-01'),
(2,'a','2017-01-08'),
(3,'a','2017-05-01'),
(4,'a','2017-01-05'),
(5,'a','2017-02-01'),
(6,'b','2017-01-01'),
(7,'b','2017-09-01'),
(8,'c','2017-10-01'),
(9,'a','2017-04-01');

DECLARE Test_Cursor CURSOR FOR  
SELECT * FROM #tmp_SampleData ORDER BY [name], [date];
OPEN Test_Cursor;

DECLARE @orderid int;
DECLARE @name nvarchar(255); 
DECLARE @date date; 

FETCH NEXT FROM Test_Cursor INTO @orderid, @name, @date;

DECLARE @current_date date = @date;
DECLARE @current_name nvarchar(255) = @name;
DECLARE @listOfIDs TABLE (orderid int);
INSERT @listOfIDs values(@orderid);

WHILE @@FETCH_STATUS = 0  
    BEGIN
       IF(@name = @current_name AND DATEDIFF(MONTH, @current_date, @date) >= 3)
          BEGIN
             SET @current_date = @date
             INSERT @listOfIDs values(@orderid)
          END
       IF(@name != @current_name)
          BEGIN
             SET @current_name = @name
             SET @current_date = @date
             INSERT @listOfIDs values(@orderid)
          END
    FETCH NEXT FROM Test_Cursor INTO @orderid, @name, @date; 
    END;  
CLOSE Test_Cursor;
DEALLOCATE Test_Cursor;
SELECT * FROM #tmp_SampleData WHERE orderid IN (SELECT orderid FROM @listOfIDs);

非常欢迎表现更佳的替代品!