Joe Green
Joe Green

Reputation: 207

Add additional row

I have following data (view):

 Declare @YourTable table ([Event] varchar(100),[Start] DateTime,[End] DateTime, [Tag] varchar(25))
  Insert Into @YourTable values
  ('10PIC700422.PV 10-PSV-700073A 10-PSV-700073B','9/9/16 10:44:05.000','9/9/16 10:48:08.000','Big'),
  ('10PIC700422.PV 10-PSV-700073A 10-PSV-700073B','9/9/16 10:44:10.000','9/9/16 10:49:40.000','Big'),
  ('10PIC700422.PV 10-PSV-700073A 10-PSV-700073B','9/9/16 10:50:03.000','9/9/16 10:51:04.000','Small'),
  ('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 12:51:07.000','4/4/16 13:58:09.000','Big'),
  ('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 14:04:04.000','4/4/16 14:29:00.000','Small'),
  ('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 14:51:02.000','4/4/16 14:58:00.000','Big'),
  ('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 15:04:06.000','4/4/16 15:29:08.000','Small'),
  ('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4-4-16 15:45:08.000','4-4-16 15:55:09.000','Big'),
  ('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4-4-16 16:22:08.000','4-4-16 16:40:09.000','Big'),
  ('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 16:50:04.000','4/4/16 16:55:00.000','Small'),
  ('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 17:05:02.000','4/4/16 17:20:00.000','Big'),
  ('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 17:22:06.000','4/4/16 17:29:08.000','Small'),
  ('11PIC41010.PV 11-PSV-401002W 11-PSV-401002D','4/4/16 16:04:01.000','4/4/16 16:45:00.000','Big');

I use following query to get result I need, group by event and order by start, and change big to small whenever small goes after big:

 Select [Event]
  ,[Start]
  ,[End] 
  ,[Tag]
  ,[Tag_new] = case when Tag='Big' and 'Small' = Lead(Tag,1,Tag) over (Partition By Event Order By Start) then 'Small' else tag end
  From  @YourTable

                                       Event    Start                   End                     Tag  Tag_new
10PIC700422.PV 10-PSV-700073A 10-PSV-700073B    2016-09-09 10:44:05.000 2016-09-09 10:48:08.000 Big   Big
10PIC700422.PV 10-PSV-700073A 10-PSV-700073B    2016-09-09 10:44:10.000 2016-09-09 10:49:40.000 Big   Small
10PIC700422.PV 10-PSV-700073A 10-PSV-700073B    2016-09-09 10:50:03.000 2016-09-09 10:51:04.000 Small Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 12:51:07.000 2016-04-04 13:58:09.000 Big   Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 14:04:04.000 2016-04-04 14:29:00.000 Small Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 14:51:02.000 2016-04-04 14:58:00.000 Big   Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 15:04:06.000 2016-04-04 15:29:08.000 Small Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 15:45:08.000 2016-04-04 15:55:09.000 Big   Big
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 16:22:08.000 2016-04-04 16:40:09.000 Big   Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 16:50:04.000 2016-04-04 16:55:00.000 Small Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 17:05:02.000 2016-04-04 17:20:00.000 Big   Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 17:22:06.000 2016-04-04 17:29:08.000 Small Small
11PIC41010.PV 11-PSV-401002W 11-PSV-401002D     2016-04-04 16:04:01.000 2016-04-04 16:45:00.000 Big   Big

I need to apply one more exception, whenever sequence below appears in Tag column in a group, it should add aditional row after small and before big with starttime, endtime and Tag_new accordingly, and starttime should be 1 sec late than previous date endtime and endtime is 1 sec late than starttime and Tag_new is "Bad":

Small
Big
Small

I'd like to get something like below:

                                       Event    Start                   End                     Tag  Tag_new
10PIC700422.PV 10-PSV-700073A 10-PSV-700073B    2016-09-09 10:44:05.000 2016-09-09 10:48:08.000 Big   Big
10PIC700422.PV 10-PSV-700073A 10-PSV-700073B    2016-09-09 10:44:10.000 2016-09-09 10:49:40.000 Big   Small
10PIC700422.PV 10-PSV-700073A 10-PSV-700073B    2016-09-09 10:50:03.000 2016-09-09 10:51:04.000 Small Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 12:51:07.000 2016-04-04 13:58:09.000 Big   Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 14:04:04.000 2016-04-04 14:29:00.000 Small Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 14:29:01.000 2016-04-04 14:29:02.000 Bad   Bad
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 14:51:02.000 2016-04-04 14:58:00.000 Big   Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 15:04:06.000 2016-04-04 15:29:08.000 Small Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 15:45:08.000 2016-04-04 15:55:09.000 Big   Big
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 16:22:08.000 2016-04-04 16:40:09.000 Big   Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 16:50:04.000 2016-04-04 16:55:00.000 Small Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 16:55:01.000 2016-04-04 16:55:02.000 Bad   Bad
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 17:05:02.000 2016-04-04 17:20:00.000 Big   Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 17:22:06.000 2016-04-04 17:29:08.000 Small Small
11PIC41010.PV 11-PSV-401002W 11-PSV-401002D     2016-04-04 16:04:01.000 2016-04-04 16:45:00.000 Big   Big

Upvotes: 2

Views: 90

Answers (2)

Joe Green
Joe Green

Reputation: 207

@Shnugo: you were really close. Thanks for solution!!!

WITH YourQueryEnhanced AS
(
Select [Event]
,[Start]
,[End] 
,[Tag]
,[Tag_new] = case when Tag='Big' and 'Small' = Lead(Tag,1,Tag) over (Partition By [Event] Order By Start) then 'Small' else tag end
,ROW_NUMBER() OVER(Partition By [Event] Order By Start) AS SortInx --You     should put a secure ORDER BY here!!!
,0 AS InnerSortInx
From  @YourTable
), BadMarked AS
(
 SELECT *
    ,CASE WHEN LAG([Tag],1) OVER(Order By SortInx)='Small' 
            AND LAG([Tag],2) OVER(Order By SortInx)='Big' 
            AND LAG([Tag],3) OVER(Order By SortInx)='Big' THEN 1 ELSE 0 END     AS BadSequence 
FROM YourQueryEnhanced 
) 
select * from
(
SELECT *
FROM BadMarked
UNION ALL 
    SELECT [Event],DATEADD(s, -1, [Start]) [Start],    [End],'Bad','Bad',SortInx-1,1,2 
FROM BadMarked 
WHERE BadMarked.BadSequence=1
) a order by [Event]
,[Start]

Upvotes: 1

Gottfried Lesigang
Gottfried Lesigang

Reputation: 67311

This design smells, but you might try something like this:

You should avoid culture specific datetime literals!

Declare @YourTable table ([Event] varchar(100),[Start] DateTime,[End] DateTime, [Tag] varchar(25))
Insert Into @YourTable values
('10PIC700422.PV 10-PSV-700073A 10-PSV-700073B','9/9/16 10:44:05.000','9/9/16 10:48:08.000','Big'),
('10PIC700422.PV 10-PSV-700073A 10-PSV-700073B','9/9/16 10:44:10.000','9/9/16 10:49:40.000','Big'),
('10PIC700422.PV 10-PSV-700073A 10-PSV-700073B','9/9/16 10:50:03.000','9/9/16 10:51:04.000','Small'),
('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 12:51:07.000','4/4/16 13:58:09.000','Big'),
('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 14:04:04.000','4/4/16 14:29:00.000','Small'),
('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 14:51:02.000','4/4/16 14:58:00.000','Big'),
('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 15:04:06.000','4/4/16 15:29:08.000','Small'),
('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4-4-16 15:45:08.000','4-4-16 15:55:09.000','Big'),
('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4-4-16 16:22:08.000','4-4-16 16:40:09.000','Big'),
('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 16:50:04.000','4/4/16 16:55:00.000','Small'),
('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 17:05:02.000','4/4/16 17:20:00.000','Big'),
('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 17:22:06.000','4/4/16 17:29:08.000','Small'),
('11PIC41010.PV 11-PSV-401002W 11-PSV-401002D','4/4/16 16:04:01.000','4/4/16 16:45:00.000','Big');

--Add a running row-number to your query and a 0 for all original rows

WITH YourQueryEnhanced AS
(
    Select [Event]
    ,[Start]
    ,[End] 
    ,[Tag]
    ,[Tag_new] = case when Tag='Big' and 'Small' = Lead(Tag,1,Tag) over (Partition By [Event] Order By Start) then 'Small' else tag end
    ,ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS SortInx --You should put a secure ORDER BY here!!!
    ,0 AS InnerSortInx
    From  @YourTable
)

--Use LAG() to detect your sequence. There is one problem with overlapping bad sequences!

,BadMarked AS
(
    SELECT *
        ,CASE WHEN LAG([Tag],1) OVER(Order By SortInx)='Small' 
                AND LAG([Tag],2) OVER(Order By SortInx)='Big' 
                AND LAG([Tag],3) OVER(Order By SortInx)='Small' THEN 1 ELSE 0 END AS BadSequence 

    FROM YourQueryEnhanced
)

--This will select all original rows and will add a bad row for each row marked as BadSequence. The SortInx is set to the prev value, the inner sortInx is set to 1, hence the ORDER BY will push the bad rows in the proper place

    SELECT *
    FROM BadMarked

    UNION ALL 

    SELECT [Event],[Start],[End],'Bad','Bad',SortInx-1,1,2 
    FROM BadMarked 
    WHERE BadMarked.BadSequence=1
    ORDER BY SortInx,InnerSortInx

Attention

This will add one more bad row to your result, as you stated this in your expected result.

The reason are your lines 3 to 7 where you have small-big-small-big-small. The middle small belongs to both sequences.

You must either solve this with more logic in the place (more calls to LAG() to look further back), where the bad sequence is detected, or you wrap the last select as one more CTE and use LAG() again to remove bad rows you don't want.

Upvotes: 1

Related Questions