Get the SUM of a DATEDIFF result - sql-server

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;

Related

How to group by week even when the count is 0

My below example works fine, the only challenge i am facing is that weeks with 0 results do not show.
Here is a sample of my code:
SELECT
DATENAME (WK, DATE) AS WEEK,
COUNT (DISTINCT COMPANY_ID) AS AMOUNT
FROM
(
SELECT COMPANY, DATE = MIN(DATE)
FROM TABLE1 A INNER JOIN TABLE2 B
ON A.ID = B.ID
WHERE YEAR(A.DATE) = '2019' AND COMPANY_ID NOT IN(SELECT COMPANY_ID FROM
TABLE1 A INNER JOIN TABLE2 B ON A.ID = B.ID AND DATE < '2019-01-01') GROUP
BY COMPANY_ID) d
GROUP BY dateadd(wk, datediff(wk, 0, DATE), 0), DATENAME(WK, DATE)
ORDER BY dateadd(wk, datediff(wk, 0, DATE), 0)
My current output looks like this:
week | amount
4 | 354
6 | 222
7 | 144
8 | 354
9 | 45
10 | 55
11 | 76
12 | 98
13 | 45
14 | 344
The result above is missing many weeks (1,2,3 and 15,16,17 etc.)
How do i get to show those with 0 count?
My desired output:
week | amount
1 | 0
2 | 0
3 | 0
4 | 354
6 | 222
7 | 144
8 | 354
9 | 45
10 | 55
11 | 76
12 | 98
13 | 45
14 | 344
15 | 0
16 | 0
17 | 0
Couple of things to note -
1) Your current query is not correct (Possibly, you have removed some portion of it to hide confidential stuff).
Ex. In the subquery named "d", the GROUP BY is on "company_id" column but "company" has been SELECT-ed.
SELECT DATENAME (WK, DATE) AS WEEK,
COUNT (DISTINCT COMPANY_ID) AS AMOUNT
FROM
(
SELECT COMPANY /*Different from group_by clause*/, DATE = MIN(DATE)
FROM TABLE1 A INNER JOIN TABLE2 B ON (A.ID = B.ID)
WHERE YEAR(A.DATE) = '2019'
AND COMPANY_ID NOT IN
(
SELECT COMPANY_ID
FROM TABLE1 A INNER JOIN TABLE2 B ON A.ID = B.ID AND DATE < '2019-01-01'
)
GROUP BY COMPANY_ID
) d
GROUP BY dateadd(wk, datediff(wk, 0, DATE), 0), DATENAME(WK, DATE)
ORDER BY dateadd(wk, datediff(wk, 0, DATE), 0)
2) I hope while editing you have not remove any clauses mistakenly.
3) Could you please post some input data to understand the output better.
(Apologies for posting here, as I don't have privilege to comment.)
First Create a temp table that has all weeks numbers
then join it with your query
DECLARE #Weeks AS Table(ID int)
DECLARE #i int = 1
WHILE #i < 53
BEGIN
INSERT INTO #Weeks (ID)
VALUES(#i)
SET #i = #i + 1
END
SELECT * FROM #Weeks
SELECT
DATENAME (WK, DATE) AS WEEK,
COUNT (DISTINCT COMPANY_ID) AS AMOUNT
FROM
(
SELECT COMPANY, DATE = MIN(DATE)
FROM TABLE1 A INNER JOIN TABLE2 B
ON A.ID = B.ID
RIGHT OUTER JOIN #Weeks W ON W.ID = DATENAME (WK, DATE)
WHERE YEAR(A.DATE) = '2019' AND COMPANY_ID NOT IN(SELECT COMPANY_ID FROM
TABLE1 A INNER JOIN TABLE2 B ON A.ID = B.ID AND DATE < '2019-01-01') GROUP
BY COMPANY_ID) d
GROUP BY dateadd(wk, datediff(wk, 0, DATE), 0), DATENAME(WK, DATE)
ORDER BY dateadd(wk, datediff(wk, 0, DATE), 0)

Get datediff from three tables

How can I get the date difference based on schedule of the employee and First Time In and Last Time Out?
Below are the queries I'm using.
select * from tbl_payroll_schedule where id in (3, 17, 18)
Output:
id schedule_description time_in time_out schedule_status
3 REST DAY 1900-01-01 00:00:00.000 1900-01-01 00:00:00.000 1
17 08:00 AM - 05:00 PM 1900-01-01 08:00:00.000 1900-01-01 17:00:00.000 1
18 08:00 AM - 12:00 PM 1900-01-01 08:00:00.000 1900-01-01 12:00:00.000 1
select mon.schedule_description as Monday,
tue.schedule_description as Tuesday,
wed.schedule_description as Wednesday,
thu.schedule_description as Thursday,
fri.schedule_description as Friday,
sat.schedule_description as Saturday,
sun.schedule_description as Sunday
from employee_default_schedule ds
LEFT JOIN tbl_payroll_schedule mon on mon.id = ds.mon_sched
LEFT JOIN tbl_payroll_schedule tue on tue.id = ds.tues_sched
LEFT JOIN tbl_payroll_schedule wed on wed.id = ds.wed_sched
LEFT JOIN tbl_payroll_schedule thu on thu.id = ds.thurs_sched
LEFT JOIN tbl_payroll_schedule fri on fri.id = ds.fri_sched
LEFT JOIN tbl_payroll_schedule sat on sat.id = ds.sat_sched
LEFT JOIN tbl_payroll_schedule sun on sun.id = ds.sun_sched
WHERE ds.employee_id = 125
Output:
select ot.id,
ot.employee_id as EID,
(el.Last_Name + ', ' + el.First_Name) as Name,
FORMAT(ot.record_time, 'ddd MM-dd-yyyy HH:mm:ss') as Time,
(CASE WHEN ot.type = 0 then 'Time In'
WHEN ot.type = 1 then 'Time Out'
END) as Status
from officer_timelogs ot
left join tbl_Employee_MasterList el on el.ID = ot.employee_id
where ot.employee_id = (CASE WHEN 125 = 0 THEN ot.employee_id else 125 END)
and ot.record_time >= CONVERT(datetime, '08/16/2018 00:00:00', 121) and ot.record_time <= CONVERT(datetime, '08/16/2018 23:59:59', 121)
order by el.Last_Name asc, ot.record_time asc
Output:
id EID Name Time Status
194664 125 MOQUETE, ABRAHAM JOSEPH Thu 08-16-2018 07:55:57 Time In
194703 125 MOQUETE, ABRAHAM JOSEPH Thu 08-16-2018 12:11:36 Time Out
194705 125 MOQUETE, ABRAHAM JOSEPH Thu 08-16-2018 12:28:12 Time In
194757 125 MOQUETE, ABRAHAM JOSEPH Thu 08-16-2018 20:45:08 Time Out
Currently I am able get the total work hours, and I want to get the Late and Overtime.
select
employee_id as EID,
FORMAT(date, 'MM-dd-yyyy') as [Date],
DATENAME(WEEKDAY, date) as [Day],
right(concat('00', diff / 4100), 2) + ':' + right(concat('00', diff % 3600 / 60), 2) + ':' + right(concat('00', diff % 60), 2) as TWH
from (select
employee_id,
[date] = cast(actual_time as date),
diff = datediff(ss, min(iif(type = 0, actual_time, null)), max(iif(type = 1, actual_time, null)))
from
officer_timelogs
where employee_id = (CASE WHEN #employee_id = 0 THEN employee_id else #employee_id END)
group by employee_id, cast(actual_time as date)
) t
where t.date >= #dateFrom and t.date <= #dateTo
order by date asc
Expected Output:
EID Date Day TWH Late OT
125 08-16-2018 Thursday 11:49:11

Incrementing while inserting sql

I have a table as below:
Department Date Budget
-----------------------------------
D1 2010-01-01 100
D2 2010-01-01 200
... ... ...
Is there a way to write an insert statement that autoincrements the month and budget for a particular department?
For instance, I want to insert data for 2010 from Jan to Dec for department D1 with increments of 10 each month. So the resultant table should look something like below
Department Date Budget
------------------------------------
D1 2010-01-01 100
D2 2010-01-01 200
D1 2010-02-01 110
D1 2010-03-01 120
D1 2010-04-01 130
... ... ...
I know this can be achieved through some scripting, but is there a way to achieve this through just insert and select statements ?
Using SQL Server (or) Postgres
For Postgres:
insert into the_table (department, "date", budget)
select d.department,
d.date + interval '1 month' * row_number() over (order by g.i),
d.budget + row_number() over (order by g.i) * 10
from the_table d, generate_series(1,11) as g(i)
where d.department = 'D1';
This assumes that at the time when this is run, only a single row exists for department D1
try something like
insert into Table values
('D1',Dateadd(month,1,
(select top 1 Date from Table order by Date Desc)),budget)
using recursive cte
;With cte(Department,[Date], Budget)
AS
(
SELECT 'D1','2010-01-01', 100 UNION ALL
SELECT 'D2','2010-01-01', 200
)
,cte2 AS
(
SELECT 0 AS val ,
0 AS val2
UNION ALL
SELECT val +1,
val2+10
FROM cte2
WHERE val<11 )
INSERT INTO the_table (department, [date], budget)
SELECT department,
[date],
CASE
WHEN rnk=0 THEN budget
ELSE budget+val2
END AS Budget
FROM (
SELECT department,
val2,
Dateadd(month,val,[date])AS [Date],
budget,
Row_number()OVER(PArtition by Department ORDER BY [Date])-1 AS Rnk
FROM Cte2 ,
Cte )dt
WHERE dt.department='D1'
Result
department Date Budget
-------------------------------------------
D1 2010-01-01 00:00:00.000 100
D1 2010-02-01 00:00:00.000 110
D1 2010-03-01 00:00:00.000 120
D1 2010-04-01 00:00:00.000 130
D1 2010-05-01 00:00:00.000 140
D1 2010-06-01 00:00:00.000 150
D1 2010-07-01 00:00:00.000 160
D1 2010-08-01 00:00:00.000 170
D1 2010-09-01 00:00:00.000 180
D1 2010-10-01 00:00:00.000 190
D1 2010-11-01 00:00:00.000 200
D1 2010-12-01 00:00:00.000 210

Group and count by 16 hours time interval not working

I am trying to get the number of records for a 16 hour time interval. Below is the code that I am using now.
;With Cte_hours as ( --hours generation
Select top(6) hr = (Row_number() over (order by (Select NULL))-1)*4 from master..spt_values
), cte2 as ( --getting range
Select DateAdd(HH, c.hr, Convert(datetime,d.dts) ) as Dts_Start, DateAdd(MS, -2, DateAdd(HH, c.hr+ 4, Convert(datetime,d.dts) ) ) Dts_end
from (select distinct convert(date, dt) as dts from TEST2 ) d
cross apply Cte_hours c
) --actual query
Select c2.Dts_Start as DT, Sum(case when t.Dt is not null then 1 else 0 end) No_of_records,LD_VOY_N,LD_VSL_M
from cte2 c2
Left Join TEST2 t
on t.Dt between c2.Dts_Start and c2.Dts_end
group by c2.Dts_Start,LD_VOY_N,LD_VSL_M
order by LD_VOY_N, LD_VSL_M, Dts_Start ASC
This code is able to count the number of records I have based on a 4,6, and 12 hour interval. However, if I try to count based on a 16 hour interval, it somehow does not work. Below is my code and output that I used for the 16 hour interval.
;With Cte_hours as ( --hours generation
Select top(6) hr = (Row_number() over (order by (Select NULL))-1)*16 from master..spt_values
), cte2 as ( --getting range
Select DateAdd(HH, c.hr, Convert(datetime,d.dts) ) as Dts_Start, DateAdd(MS, -2, DateAdd(HH, c.hr+ 16, Convert(datetime,d.dts) ) ) Dts_end
from (select distinct convert(date, dt) as dts from TEST2 ) d
cross apply Cte_hours c
) --actual query
Select c2.Dts_Start as DT, Sum(case when t.Dt is not null then 1 else 0 end) No_of_records,LD_VOY_N,LD_VSL_M
from cte2 c2
Left Join TEST2 t
on t.Dt between c2.Dts_Start and c2.Dts_end
group by c2.Dts_Start,LD_VOY_N,LD_VSL_M
order by LD_VOY_N, LD_VSL_M, Dts_Start ASC
Result:
DT No_of_records LD_VOY_N LD_VSL_M
2017-05-05 16:00:00.000 14 0002W pqo emzmnwp
2017-05-06 00:00:00.000 14 0002W pqo emzmnwp
2017-05-06 08:00:00.000 12 0002W pqo emzmnwp
2017-05-06 16:00:00.000 12 0002W pqo emzmnwp
2017-05-01 16:00:00.000 1 0007E omq ynzmeoyn
2017-05-02 00:00:00.000 1 0007E omq ynzmeoyn
It is taking the 8 hour timing as well. Do any of you have any idea why?

Count number of items which hadn't been checked so far in the last x months

We have a list of items. Each item may be checked/examined one or more times in the last #FromDate to #ToDate (12 months, for example). How do we count the number of items which were checked in a month that had never been check since #FromDate and display that count monthly.
The result would look like below:
2014-05-01 00:00:00.000 1 May 2014 381
2014-06-01 00:00:00.000 2 June 2014 296
2014-07-01 00:00:00.000 3 July 2014 24
2014-08-01 00:00:00.000 4 August 2014 260
2014-09-01 00:00:00.000 5 September 2014 249
2014-10-01 00:00:00.000 6 October 2014 177
2014-11-01 00:00:00.000 7 November 2014 298
2014-12-01 00:00:00.000 8 December 2014 274
2015-01-01 00:00:00.000 9 January 2015 41
2015-02-01 00:00:00.000 10 February 2015 0
2015-03-01 00:00:00.000 11 March 2015 0
2015-04-01 00:00:00.000 12 April 2015 0
So far we could count the number of items which were checked monthly by using the following query:
;WITH d AS
(
SELECT DATEADD(MONTH, n, DATEADD(MONTH, DATEDIFF(MONTH, 0, '2014-05-15'), 0)) as d, ROW_NUMBER() OVER (ORDER BY n) as rn
FROM ( SELECT TOP (DATEDIFF(MONTH, '2014-05-15', '2015-04-15') + 1)
n = ROW_NUMBER() OVER (ORDER BY [object_id]) - 1
FROM sys.all_objects ORDER BY [object_id] ) AS n
)
SELECT
d.d,
d.rn,
DATENAME(MONTH, d.d) as [Month],
YEAR(d.d) as [Year],
COUNT(DISTINCT ItemNumber) AS Count
FROM d LEFT OUTER JOIN ItemCheck
ON CheckedTime >= d.d
AND CheckedTime < DATEADD(MONTH, 1, d.d)
GROUP BY d.d, d.rn
ORDER BY d.d;
However, we still can't figure out how to count the number of items which were checked say in July 2014 but had never been checked in May and June 2014.
A simple single query below would be able to display that for a particular month but that doesn't display in monthly.
select count(distinct ItemNumber) from ItemCheck
where CheckTime >= '2014-07-01' AND CheckTime < '2014-08-01' and
ItemNumber NOt in (SELECT ItemNumber FROM ItemCheck as t1 where t1.CheckTime >= '2014-05-01' AND t1.CheckTime < '2014-07-01')
order by ItemNumber
Update: The ItemCheck table looks like below:
CheckID | ItemNumber | CheckTime
1 i1 2014-05-02
2 i4 2014-06-12
3 i5 2014-07-03
4 i1 2014-08-01
5 i1 2014-08-02
6 i2 2014-09-15
7 i3 2014-10-11
Suppose you have a table called months with one column called month.
Then you could do it something along these lines:
DECLARE #date DATE
SET #date = '2014-01-01'
SELECT months.month AS currentMonth, COUNT(ItemNumber) ItemNumber from ItemCheck
CROSS JOIN months
WHERE CheckTime >= dateadd(m, months.month - 1, #date) AND CheckTime < dateadd(m, months.month, #date) and
ItemNumber NOT IN (SELECT ItemNumber FROM ItemCheck AS t1 WHERE t1.CheckTime >= DATEADD(m, months.month - 3, #date) AND t1.CheckTime < dateadd(m, months.month - 1, #date))
GROUP BY month
ORDER BY ItemNumber
You could also do it with a function, but you have to write it (function is called dbo.Split and you could write it this way: select data from dbo.Split(',', '1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12'). This way you could avoid creating another table (in-memory or a real one..)
If you want the code for dbo.Split I can provide it.

Resources