How do I subtract two columns with datetime in SQLite? - sql

I am learning SQLite for work and I am trying to subtract 'Enddate' column fromn 'Startdate' column, which contain date and time. Soemthing like this:
Startdate 3/15/18 16:00 3/28/18 17:00
Enddate 3/19/18 00:00 3/20/18 00:00
My table's name is data1. I tried this:
select *,
strftime('%m/%d/%y %H:%M', 'data1.Enddate') -
(strftime('%m/%d/%y %H:%M', 'data1.Startdate')) as TimeOff
from data1;
But this gives me all 'Null' values.
If you could help me with this I would really appreciate that. That you so much!

Two possible reasons you got NULL (likely because of a silent error):
1) Your dates are malformed when you create them. They should be yyyy-mm-dd HH:MM:SS format instead.
2) Not having a closing semicolon in one of your queries. I see it in the one above, but if the one where you insert your test rows didn't close properly, you may not
My test query:
https://dbfiddle.uk/?rdbms=sqlite_3.8&fiddle=8b9a168291bbc08c74a895ce22ab41ac
Setup
CREATE TABLE data1 (foo int, StartDate datetime, EndDate datetime) ;
INSERT INTO data1 (foo, StartDate, EndDate)
VALUES (1,'2018-03-15 16:00:00', '2018-03-28 17:00:00')
, (2,'2018-03-19 00:00:00', '2018-03-20 00:00:00') ;
The Query
SELECT foo, StartDate, EndDate
, julianday(EndDate)-julianday(StartDate) AS TimeOffInDays
, CAST((julianday(EndDate) - julianday(StartDate))*24 AS real) AS TimeOffInHours
FROM data1 ;
Which gives us...
| foo | StartDate | EndDate | TimeOffInDays | TimeOffInHours |
=========================================================================================
| 1 | 2018-03-15 16:00:00 | 2018-03-28 17:00:00 | 13.041666666977 | 313.00000000745 |
| 2 | 2018-03-19 00:00:00 | 2018-03-20 00:00:00 | 1 | 24 |

Related

Vertica String Timezone conversion

I have a list of 'HH24:MI:SS' stored as a string and I need to factor in the timezone.
Is there a way to select a.hour at timezone from database with how it's currently stored?
11:30:00
11:00:00
12:00:00
not sure if there's a way or not. I've tried converting to a date or timestamp but no luck since it's stored as a string. I feel like theres a simple way but I'm not seeing it
Do you mean this?
WITH
indata(s) AS (
SELECT '11:30:00'
UNION ALL SELECT '11:00:00'
UNION ALL SELECT '12:00:00'
)
SELECT
s::TIME AS the_time
, s::TIME AT TIMEZONE 'America/New_York' AS the_other_time
, HOUR(s::TIME) AS the_hour
, HOUR(s::TIME AT TIMEZONE 'America/New_York') AS the_other_time
FROM indata;
-- out the_time | the_other_time | the_hour | the_other_time
-- out ----------+----------------+----------+----------------
-- out 11:30:00 | 05:30:00-05 | 11 | 5
-- out 11:00:00 | 05:00:00-05 | 11 | 5
-- out 12:00:00 | 06:00:00-05 | 12 | 6

Pivot all Time Data on Date Column

I need to create a report in SQL Server Reporting Service. The source table/query data is structured as follows:
CNum | EmpNo | TDate | TimeIn | TimeOut
100 | 2 | 12/4/2019 | 7:00 AM | 12:00 PM
100 | 2 | 12/4/2019 | 12:30 PM | 3:30 PM
100 | 2 | 12/5/2019 | 7:00 AM | 12:00 PM
100 | 2 | 12/5/2019 | 12:30 PM | 3:30 PM
I need the report output to be displayed as follows (or something similar, just need to show the TDate as columns and any related time entries based on the CNum as rows).
CNum | 12/4/2019 | 12/5/2019 |
100 | 7:00 AM | 7:00 AM |
| 12:00 PM | 12:00 PM |
100 | 12:30 PM | 12:30 PM |
| 3:30 PM | 3:30 PM |
I have tried using the Matrix Tablix but this forces the group to only return on record per day, when there may be multiple. My goal is to write a SQL Query (CTE or PIVOT) which will give me the report data in the correct format so I will not have to get crazy in the report designer.
I am familiar with SQL but for some reason I cannot get any query to output (Pivot) and include both records for the day.
Any help/guidance will be much appreciated.
You can do this easily in SSRS with a small change to your dataset query.
I reproduced your sample data with the following
DECLARE #t TABLE(CNum int, EMpNo int, TDate Date, TimeIn Time, [Timeout] Time)
INSERT INTO #t VALUES
(100, 2, '2019/12/04', '07:00', '12:00'),
(100, 2, '2019/12/04', '12:30', '15:30'),
(100, 2, '2019/12/05', '07:00', '12:00'),
(100, 2, '2019/12/05', '12:30', '15:30')
SELECT *, ROW_NUMBER() OVER(PARTITION BY TDate, Cnum ORDER BY TimeIn) as RowN FROM #t
Note: I added the RowN column which gives each row a unique number within each TDate and CNum. We add this to the CNum group in the matrix (so it groups by CNum then RowN)
Here's the final design including the row and column groups (Column group is just by TDate)
To get the 2nd row I right clicked the [TimeIn] 'cell' and did "Insert Row = > Inside Group - Below"
The final output looks like this
I think, you may take it fwd from Efficiently convert rows to columns in sql server
Here is the answer :
With CTE as (
Select
CNum,
TDate,
TimeIn as [Time],
'In' as [Action]
From TimeTable
Union All
Select
CNum,
TDate,
[TimeOut] as [Time],
'Out' as [Action]
From TimeTable
)
Select
*
From CTE
Pivot(min([Time]) for TDate in ([2019-12-04],[2019-12-05])) as pivot_table
union all
Select
*
From CTE
Pivot(max([Time]) for TDate in ([2019-12-04],[2019-12-05])) as pivot_table

Reporting on time information using start and end time

Is it possible to create a report that sums hours for a day grouped by an Id using a start and end time stamp?
I need to be able to split time that spans days and take part of that time and sum to the correct date group.
NOTE: The date ids are to a date dimension table.
------------------------------------------------------------------------------
TaskId | StartDateId | EndDateId | StartTime | EndTime
------------------------------------------------------------------------------
2 | 20190317 | 20190318 | 2019-03-17 16:30:00 | 2019-03-18 09:00:00
------------------------------------------------------------------------------
1 | 20190318 | 20190318 | 2019-03-18 09:00:00 | 2019-03-18 16:30:00
------------------------------------------------------------------------------
2 | 20190318 | 20190319 | 2019-03-18 16:30:00 | 2019-03-19 09:00:00
------------------------------------------------------------------------------
So based on this, the desired report output would be:
-------------------------
Date | Task | Hours
-------------------------
2019-03-17 | 2 | 7.5
-------------------------
2019-03-18 | 1 | 7.5
-------------------------
2019-03-18 | 2 | 16.5
-------------------------
...
The only working solution I have managed to implement is splitting records so that no record spans multiple days. I was hoping to find a report query solution, rather than an ETL base based solution.
I have tried to simulate your problem here: https://rextester.com/DEV45608 and I hope it helps you :) (The CTE GetDates can be replaced by your date dimension)
DECLARE #minDate DATE
DECLARE #maxDate DATE
CREATE TABLE Tasktime
(
Task_id INT,
Start_time DATETIME,
End_time DATETIME
);
INSERT INTO Tasktime VALUES
(2,'2019-03-17 16:30:00','2019-03-18 09:00:00'),
(1,'2019-03-18 09:00:00','2019-03-18 16:30:00'),
(2,'2019-03-18 16:30:00','2019-03-19 09:00:00');
SELECT #mindate = MIN(Start_time) FROM Tasktime;
SELECT #maxdate = MAX(End_time) FROM Tasktime;
;WITH GetDates AS
(
SELECT 1 AS counter, #minDate as Date
UNION ALL
SELECT counter + 1, DATEADD(day,counter,#minDate)
from GetDates
WHERE DATEADD(day, counter, #minDate) <= #maxDate
)
SELECT counter, Date INTO #tmp FROM GetDates;
SELECT
g.Date,
t.Task_id,
SUM(
CASE WHEN CAST(t.Start_time AS DATE) = CAST(t.End_time AS DATE) THEN
DATEDIFF(second, t.Start_time, t.End_time) / 3600.0
WHEN CAST(t.Start_time AS DATE) = g.Date THEN
DATEDIFF(second, t.Start_time, CAST(DATEADD(day,1,g.Date) AS DATETIME)) / 3600.0
WHEN CAST(t.End_time AS DATE) = g.Date THEN
DATEDIFF(second, CAST(g.Date AS DATETIME), t.End_time) / 3600.0
ELSE
24.0
END) AS hours_on_the_day_for_the_task
from
#tmp g
INNER JOIN
Tasktime t
ON
g.Date BETWEEN CAST(t.Start_time AS DATE) AND CAST(t.End_time AS DATE)
GROUP BY g.Date, t.Task_id
The Desired Date can be joined to the date dimension and return the "calendar date" and you can show that date in the report.
As for the HOURS.. when you are retrieving your dataset in SQL, just do this.. it is as simple as:
cast(datediff(MINUTE,'2019-03-18 16:30:00','2019-03-19 09:00:00') /60.0 as decimal(13,1)) as 'Hours'
So in your case it would be
cast(datediff(MINUTE,sometable.startdate,sometable.enddate) /60.0 as decimal(13,1)) as 'Hours'
Just doing a HOUR will return the whole hour.. and dividing by 60 will return a whole number. Hence the /60.0 and the cast

SQLite: Sum of differences between two dates group by every date

I have a SQLite database with start and stop datetimes
With the following SQL query I get the difference hours between start and stop:
SELECT starttime, stoptime, cast((strftime('%s',stoptime)-strftime('%s',starttime)) AS real)/60/60 AS diffHours FROM tracktime;
I need a SQL query, which delivers the sum of multiple timestamps, grouped by every day (also whole dates between timestamps).
The result should be something like this:
2018-08-01: 12 hours
2018-08-02: 24 hours
2018-08-03: 12 hours
2018-08-04: 0 hours
2018-08-05: 1 hours
2018-08-06: 14 hours
2018-08-07: 8 hours
You can try this, use CTE RECURSIVE make a calendar table for every date start time and end time, and do some calculation.
Schema (SQLite v3.18)
CREATE TABLE tracktime(
id int,
starttime timestamp,
stoptime timestamp
);
insert into tracktime values
(11,'2018-08-01 12:00:00','2018-08-03 12:00:00');
insert into tracktime values
(12,'2018-09-05 18:00:00','2018-09-05 19:00:00');
Query #1
WITH RECURSIVE cte AS (
select id,starttime,date(starttime,'+1 day') totime,stoptime
from tracktime
UNION ALL
SELECT id,
date(starttime,'+1 day'),
date(totime,'+1 day'),
stoptime
FROM cte
WHERE date(starttime,'+1 day') < stoptime
)
SELECT strftime('%Y-%m-%d', starttime),(strftime('%s',CASE
WHEN totime > stoptime THEN stoptime
ELSE totime
END) -strftime('%s',starttime))/3600 diffHour
FROM cte;
| strftime('%Y-%m-%d', starttime) | diffHour |
| ------------------------------- | -------- |
| 2018-08-01 | 12 |
| 2018-09-05 | 1 |
| 2018-08-02 | 24 |
| 2018-08-03 | 12 |
View on DB Fiddle

SQL Total time based on Timestamp and States

I have a table like this:
Timestamp | State
01-jan-2016 00:01:00 | ON
01-jan-2016 00:02:00 | OFF
01-jan-2016 00:02:01 | ON
01-jan-2016 00:03:00 | OFF
A Sample result would look like, considering NOW is 01-Jan-2016 00:03:10.
State | TotalTime
ON | 00:01:59
OFF | 00:00:11
I'd like to have a query that returns the total time [in hours, mins and secs] for each of the states. Is that possible using SQL Server Express 2012? Any ideas/directions I should take?
A small change would be required if you want to see over 24 hours
Declare #YourTable table (Timestamp datetime,State varchar(25))
Insert Into #YourTable values
('01-jan-2016 00:01:00','ON'),
('01-jan-2016 00:02:00','OFF'),
('01-jan-2016 00:02:01','ON'),
('01-jan-2016 00:03:00','OFF')
Declare #Default DateTime ='01-Jan-2016 00:03:10'
;with cteBase as (
Select *,NextTime = Lead(TimeStamp,1,#Default) over (Order By TimeStamp)
From #YourTable
)
Select State
,Duration=cast(DateAdd(SECOND,sum(DateDiff(SECOND,TimeStamp,NextTime)),cast('1900-01-01 00:00:00' as datetime)) as time)
From cteBase
Group By State
Returns
State Duration
OFF 00:00:11
ON 00:01:59
Just a quick note.
Lead(TimeStamp,1,TimeStamp) could be Lead(TimeStamp,1,GetDate()) if you want final state to current.