I have a SQL statement (MS SQL Server 2012) that makes a simple calculation of the differences in dates in some records. I want to return the total / sum of the DATEDIFFs as well.
This is my query:
with cte as (
select ROW_NUMBER () OVER (ORDER BY Date) as ID, Die_ID, Date, Status
from Tooling_Status
where (date between '2018-02-27 00:00:00' and '2019-02-27 11:59:59')
and Date is not null)
select DATEDIFF (ss, c1.Date, min (c2.Date)) as Seconds, convert (nvarchar (10), c1.Date, 120) as DIA
from cte c1
left outer join cte c2
on c1.Date < c2.Date and c1.Die_ID = c2.Die_ID
where c1.Status = 2 and c2.Status = 1
group by c1.Date
order by DIA desc
And this my result:
Seconds DAY
2253 2019-02-27
166 2019-02-27
17 2019-02-27
104 2019-02-27
36 2019-02-27
11 2019-02-07
20 2019-02-07
32 2019-02-07
22 2019-02-07
27 2019-02-07
33 2019-02-07
15 2019-02-07
34 2019-02-07
120 2019-02-04
99420 2019-01-07
60 2018-09-26
I need this result:
Seconds DAY
2732 2019-02-27
194 2019-02-07
120 2019-02-04
99420 2019-01-07
60 2018-09-26
Thanks For Help!
Few adjustments
Extra GROUP BY using a derived table
Removed unnecessary casts to a string
Formatting...
SQL:
WITH cte
AS (SELECT ROW_NUMBER() OVER (ORDER BY Date) AS ID,
Die_ID,
Date,
Status
FROM Tooling_Status
WHERE (date BETWEEN '2018-02-27 00:00:00' AND '2019-02-27 11:59:59' )
AND Date IS NOT NULL
)
SELECT SUM(d.Seconds) AS Seconds
, d.DIA AS [Day]
FROM (
SELECT DATEDIFF(ss, c1.Date, MIN(c2.Date)) AS Seconds,
CAST(c1.Date AS DATE) AS DIA
FROM cte c1
LEFT OUTER JOIN cte c2
ON c1.Date < c2.Date
AND c1.Die_ID = c2.Die_ID
WHERE c1.Status = 2 AND c2.Status = 1
GROUP BY c1.Date
) d
GROUP BY d.DIA
ORDER BY [Day] DESC;
This is for SQL Server 2008/2012.
I have the following dataset with the claim start date and end date. I want to calculate the number of days when there are back to back claims where the claim start date of the next date is one day after the claim end date of the previous date, making it a continuous service.
If there is a break in service, like for member id 1002 where the claim end of 05/15 and next one starts on 05/18, the count should restart.
MemberID Claim Start Claim End Claim_ID
1001 2016-04-01 2016-04-15 ABC11111
1001 2016-04-16 2016-04-30 ABC65465
1001 2016-05-01 2016-05-15 ABC51651
1001 2016-05-16 2016-06-15 ABC76320
1002 2016-04-01 2016-04-15 ABC74563
1002 2016-04-16 2016-04-30 ABC02123
1002 2016-05-01 2016-05-15 ABC02223
1002 2016-05-18 2016-06-15 ABC66632
1002 2016-06-16 2016-06-30 ABC77447
1002 2016-07-10 2016-07-31 ABC33221
1002 2016-08-01 2016-08-10 ABC88877
So effectively, I want the following output. Min of the very first claim start date, max of the claim end date when there is no gap in coverage between multiple claims. If there is a gap in coverage, the count starts over and the min of the start date of the 1st claim and the max of the claim end date until there is no gap in coverage between multiple claims.
MemberID Claim_Start Claim_End Continuous_Service_Days
1001 2016-04-01 2016-06-15 76
1002 2016-04-01 2016-05-15 45
1002 2016-05-18 2016-06-30 44
1002 2016-07-10 2016-08-10 32
I have tried while loops, CTE's and I have also tried the following table to first get all the dates between the claims. But I am having problems with counting the days between consecutive dates and to reset the count if there is a break in coverage.
Master.dbo.spt_values
Any help is appreciated. Thanks!
You need to find the gaps first.
This solution uses a Tally Table to generate the dates first from ClaimStart to ClaimEnd. Then using the generated dates, get the gaps using this method.
Now that you have the gaps, you can now use GROUP BY to ge the MIN(ClaimStart) and MAX(ClaimStart):
WITH E1(N) AS( -- 10 ^ 1 = 10 rows
SELECT 1 FROM(VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))t(N)
),
E2(N) AS(SELECT 1 FROM E1 a CROSS JOIN E1 b), -- 10 ^ 2 = 100 rows
E4(N) AS(SELECT 1 FROM E2 a CROSS JOIN E2 b), -- 10 ^ 4 = 10,000 rows
CteTally(N) AS(
SELECT TOP(SELECT MAX(DATEDIFF(DAY, ClaimStart, ClaimEnd) + 1) FROM tbl)
ROW_NUMBER() OVER(ORDER BY(SELECT NULL))
FROM E4
),
CteDates AS( -- Generate the dates from ClaimStart to ClaimEnd
SELECT
t.MemberID,
dt = DATEADD(DAY, ct.N - 1, t.ClaimStart)
FROM tbl t
INNER JOIN CteTally ct
ON DATEADD(DAY, ct.N - 1, t.ClaimStart) <= t.ClaimEnd
),
CteGrp AS( -- Find gaps and continuous dates
SELECT *,
rn = DATEADD(DAY, - ROW_NUMBER() OVER(PARTITION BY MemberID ORDER BY dt), dt)
FROM CteDates
)
SELECT
MemberID,
ClaimStart = MIN(dt),
ClaimEnd = MAX(dt),
Diff = DATEDIFF(DAY, MIN(dt), MAX(dt)) + 1
FROM CteGrp
GROUP BY MemberID, rn
ORDER BY MemberID, ClaimStart;
ONLINE DEMO
Declare #YourTable table (MemberID int,[Claim Start] date,[Claim End] date,[Claim_ID] varchar(25))
Insert Into #YourTable values
(1001,'2016-04-01','2016-04-15','ABC11111'),
(1001,'2016-04-16','2016-04-30','ABC65465'),
(1001,'2016-05-01','2016-05-15','ABC51651'),
(1001,'2016-05-16','2016-06-15','ABC76320'),
(1002,'2016-04-01','2016-04-15','ABC74563'),
(1002,'2016-04-16','2016-04-30','ABC02123'),
(1002,'2016-05-01','2016-05-15','ABC02223'),
(1002,'2016-05-18','2016-06-15','ABC66632'),
(1002,'2016-06-16','2016-06-30','ABC77447'),
(1002,'2016-07-10','2016-07-31','ABC33221'),
(1002,'2016-08-01','2016-08-10','ABC88877')
;with cte0(N) as (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N))
,cte1(R,D) as (Select Row_Number() over (Order By (Select Null))
,DateAdd(DD,-1+Row_Number() over (Order By (Select Null)),(Select MinDate=min([Claim Start]) From #YourTable))
From cte0 N1, cte0 N2, cte0 N3, cte0 N4)
Select MemberID
,[Claim Start] = Min([Claim Start])
,[Claim End] = Max([Claim End])
,Continuous_Service_Days = count(*)
From (
Select *,Island = R - Row_Number() over (Partition By MemberID Order by [Claim Start])
From #YourTable A
Join cte1 B on D Between [Claim Start] and [Claim End]
) A
Group By MemberID,Island
Order By 1,2
Returns
MemberID Claim Start Claim End Continuous_Service_Days
1001 2016-04-01 2016-06-15 76
1002 2016-04-01 2016-05-15 45
1002 2016-05-18 2016-06-30 44
1002 2016-07-10 2016-08-10 32
i have following table:
id insertDate
1 2015-01-01
22 2015-01-02
43 2015-01-03
46 2015-01-06
124 2015-01-07
In the end i want to have a possiblity to group the rows that differ exaclty in one day so in that case
id insertDate groups
1 2015-01-01 1
22 2015-01-02 1
43 2015-01-03 1
46 2015-01-06 2
124 2015-01-07 2
How is this possible? I bet it is some fancy window function usage
This is a "gaps and islands" problem.
One approach is below. This works on SQL Server 2005+. I have assumed that insertDate is unique as per your example data.
WITH CTE
AS (SELECT *,
DATEDIFF(DAY, 0, [insertDate]) - ROW_NUMBER() OVER (ORDER BY ID) AS Grp
FROM YourTable)
SELECT [id],
[insertDate],
DENSE_RANK() OVER (ORDER BY Grp) AS Grp
FROM CTE
I need to calculate break time taken by employee, sample shown here:
Userid Date_time
------ ---------
1001 9/1/15 10:31 AM
1001 9/1/15 11:51 AM
1001 9/1/15 11:58 AM
1001 9/1/15 2:02 PM
1001 9/1/15 2:38 PM
1001 9/1/15 4:37 PM
1001 9/1/15 5:12 PM
1001 9/1/15 6:32 PM
1001 9/1/15 6:34 PM
1001 9/1/15 7:39 PM
1001 9/1/15 7:42 PM
1001 9/1/15 7:53 PM
Hence I don't want first and last record because it will be calculated as total working hours.
Expected result:
Userid break_time_MIN
------ --------------
1001 83
Please suggest how I can calculate the break time for each employee.
First, you want to remove the first and last row. After that, you want to group two consecutive rows and then get their difference. Finally, compute for the SUM of all the differences:
WITH Cte AS(
SELECT *,
grp = rn - (rn % 2 + 1)
FROM (
SELECT *,
rn = ROW_NUMBER() OVER(PARTITION BY Userid ORDER BY Date_time),
rnd = ROW_NUMBER() OVER(PARTITION BY Userid ORDER BY Date_time DESC)
FROM #tbl
) t
WHERE rn <> 1 AND rnd <> 1
),
CteFinal AS(
SELECT
Userid,
BreakDuration = DATEDIFF(MINUTE, MIN(Date_time), MAX(Date_time))
FROM Cte
GROUP BY
Userid, grp
)
SELECT
Userid,
break_time_MIN = SUM(BreakDuration)
FROM CteFinal
GROUP BY UserId;
ONLINE DEMO
---------------------
Result:
---------------------
Userid break_time_MIN
------ --------------
1001 83
;WITH cte AS (
SELECT Userid,
Date_time,
ROW_NUMBER() OVER (PARTITION BY UserId ORDER BY UserId, Date_time) as RN
FROM YourTableName)
SELECT r1.Userid, SUM(DATEDIFF(MINUTE,r1.Date_time,r2.Date_time)) as break_time
FROM cte r1
INNER JOIN cte r2
ON r1.Userid = r2.Userid AND r1.RN + 1 = r2.RN
WHERE r1.RN % 2 = 0
GROUP BY r1.Userid
Output:
Userid break_time
1001 83
I have a table PriceDate with two columns PriceId and PriceDate with 3-4 entries per month.
I want to retrieve last inserted PriceDate for each month.
This is my table
PriceDate PriceId
2012-01-07 00:00:00.000 1
2012-01-14 00:00:00.000 2
2012-01-21 00:00:00.000 3
2012-01-28 00:00:00.000 4
2012-02-04 00:00:00.000 5
2012-02-11 00:00:00.000 6
2012-02-18 00:00:00.000 7
2012-02-25 00:00:00.000 8
I need this output
PriceDate DateFormat PriceId
2012-01-28 00:00:00.000 Jan 2012 4
2012-02-25 00:00:00.000 Feb 2012 8
This seems to do the trick:
declare #t table (PriceDate datetime not null, PriceId int not null)
insert into #t(PriceDate,PriceId) values
('2012-01-07T00:00:00.000',1),
('2012-01-14T00:00:00.000',2),
('2012-01-21T00:00:00.000',3),
('2012-01-28T00:00:00.000',4),
('2012-02-04T00:00:00.000',5),
('2012-02-11T00:00:00.000',6),
('2012-02-18T00:00:00.000',7),
('2012-02-25T00:00:00.000',8)
;With Numbered as (
select *,
ROW_NUMBER() OVER (
PARTITION BY DATEADD(month,DATEDIFF(month,0,PriceDate),0)
ORDER BY PriceDate desc) as rn
from #t
)
select PriceDate,
RIGHT(CONVERT(varchar(20),PriceDate,106),8) [Dateformat],
PriceId
from Numbered where rn=1
The DATEADD/DATEDIFF trick is to basically round every date to the start of its respective month.
Result:
PriceDate Dateformat PriceId
----------------------- -------- -----------
2012-01-28 00:00:00.000 Jan 2012 4
2012-02-25 00:00:00.000 Feb 2012 8
Similar to #Damian_The_Unbeliever's but using the YEAR() and Month() functions
;WITH DateOrdered
AS
(
SELECT PriceDate, PriceId,
ROW_NUMBER() OVER (
PARTITION BY YEAR(PriceDate), MONTH(PriceDate)
ORDER BY PriceDate DESC) As Num
from PriceDate
)
SELECT PriceDate, RIGHT(CONVERT(varchar(20),PriceDate,106),8) [Dateformat], PriceId
FROM DateOrdered
WHERE Num = 1