P_K
P_K

Reputation: 43

Split single row into multiple rows based on Date and time in SQL Server

I want to split a single row into multiple rows based on time. below are the example.

SrNo    Notification    StartDate                  EndDate
---------------------------------------------------------------------------
1       001003741915    2018-08-20 07:27:00.000    2018-08-21 16:23:00.000
2       001003779670    2018-08-21 03:36:00.000    2018-08-21 04:36:00.000
3       001003779830    2018-08-21 04:36:00.000    2018-08-21 21:35:00.000

Expected output is below:

SrNo    Notification    StartDate                  EndDate
---------------------------------------------------------------------------
1       001003741915    2018-08-20 07:27:00.000    2018-08-21 05:59:00.000
1       001003741915    2018-08-21 06:00:00.000    2018-08-21 16:23:00.000
2       001003779670    2018-08-21 03:36:00.000    2018-08-21 04:36:00.000
3       001003779830    2018-08-21 04:36:00.000    2018-08-21 05:59:00.000
3       001003779830    2018-08-21 06:00:00.000    2018-08-21 21:35:00.000

Day start from 06:00 AM to next day 06:00 AM. When EndDate time is grated than 06:00 AM then split this date in two rows. first row end date is 2018-08-21 05:59:00.000 and next row start 2018-08-21 06:00:00.000.

Upvotes: 2

Views: 5489

Answers (4)

Pedro Acácio
Pedro Acácio

Reputation: 139

Based on Nitika answer I was able to do this in MySQL and solve a similar problem:

WITH RECURSIVE CTE (id, name, start_dt, end_dt) AS (
    SELECT id, name, cast(start_date as date) as start_dt, cast(end_date as date) as end_dt FROM event e1
    UNION ALL
    SELECT e2.id, e2.name, DATE_ADD(e2.start_dt, INTERVAL 1 DAY) as start_dt, e2.end_dt
    FROM CTE e2
    WHERE e2.start_dt < e2.end_dt
)
SELECT * FROM CTE order by start_dt

Upvotes: 0

NP007
NP007

Reputation: 688

Below Query will help you.

CREATE TABLE #test
(
    Notifications varchar(50)
    ,StartDate datetime
    ,EndDate Datetime
    ,Id int
)

INSERT into #test
select              '001003741915','2018-08-20 07:27:00.000','2018-08-21 16:23:00.000',1
UNION select        '001003779670','2018-08-21 03:36:00.000','2018-08-21 04:36:00.000',2
UNION select        '001003779830','2018-08-21 04:36:00.000','2018-08-21 21:35:00.000',3
UNION select        '001003779835','2018-08-21 04:36:00.000','2018-08-24 21:35:00.000',4

;with cte
As (  SELECT 
        ID,Notifications,StartDate,dateadd(d, datediff(d, 1, StartDate+1), '06:00') as StartOfDay, EndDate,dateadd(d, datediff(d, 1, EndDate+1), '06:00')  as EndDayOfDate
    FROM #test
)
, Result
AS (


    select Id
            ,Notifications
            ,StartDate 
            ,CASE WHEN StartOfDay BETWEEN StartDate AND EndDate THEN  StartOfDay
                  WHEN ENDDate <StartOfDay THEN ENDDate
                  WHEN ENDDate <EndDayOfDate THEN ENDDate
                ELSE  EndDayOfDate  END AS  EndDate 
    from cte

    union ALL
    Select T.Id
            ,T.Notifications
            ,R.EndDate As StartDate
            ,CASE WHEN R.EndDate+1 < T.EndDate THEN R.EndDate+1 ELSE  T.EndDate   END AS EndDate 
    from cte  T
    INNER JOIN Result R
    ON R.Notifications=T.Notifications
    WHERE  R.EndDate <T.EndDate

)

SELECT * FROM Result order by id

Upvotes: 2

Amin Mozhgani
Amin Mozhgani

Reputation: 604

if there is only one day or less difference between startdate and enddate

If we call your table t1:

SELECT [SrNo]
      ,[Notification]
      ,[StartDate]
      ,[EndDate]

  FROM [t1]
  where DATEADD(MINUTE, 59,   DATEADD(HOUR, 5, CAST(CAST(enddate AS DATE) AS DATETIME))) > enddate
  union 
  SELECT [SrNo]
      ,[Notification]
      ,[StartDate]
      ,DATEADD(MINUTE, 59,   DATEADD(HOUR, 5, CAST(CAST(enddate AS DATE) AS DATETIME))) [EndDate]

  FROM [t1]
  where DATEADD(MINUTE, 59,   DATEADD(HOUR, 5, CAST(CAST(enddate AS DATE) AS DATETIME))) between startdate and enddate

  union 
  SELECT [SrNo]
      ,[Notification]
      ,DATEADD(MINUTE, 00,   DATEADD(HOUR, 6, CAST(CAST(enddate AS DATE) AS DATETIME))) [StartDate]
      , [EndDate]

  FROM [t1]
  where DATEADD(MINUTE, 59,   DATEADD(HOUR, 5, CAST(CAST(enddate AS DATE) AS DATETIME))) between startdate and enddate

  order by srno
  ,enddate 

Upvotes: 0

Nitika
Nitika

Reputation: 463

You can achieve this by using recursive CTE

WITH CTE AS (
SELECT ID, Notification, StartDate, EndDate 
FROM TAB1
UNION ALL
SELECT ID, Notification, DATEADD(DD,1,StartDate), EndDate 
FROM CTE
WHERE cast(StartDate as date) < cast(EndDate as date)
)
SELECT * FROM CTE order by id

Upvotes: 1

Related Questions