SQL convert to week day and hh:mm - sql

Not sure can we convert datetime field column, for example:
Contactdate
2020-03-12 16:20:34.000
2020-01-01 00:52:34.000
become
contact date
Wednesday 12:52
Thursday 04:20

DECLARE #d table(Contactdate datetime);
INSERT #d VALUES('2020-03-12 16:20:34.000'),('2020-01-01 00:52:34.000');
SELECT contact = DATENAME(WEEKDAY, Contactdate),
date = CONVERT(CHAR(5), Contactdate, 108)
FROM #d;
I tend to stay away from FORMAT() - while convenient and flexible, it does not scale in my testing.

In SQL Server, you can use format() for this:
select format(contactdate, N'dddd hh\:mm') formated_date
from mytable
Demo on DB Fiddle:
select contactdate, format(contactdate, N'dddd hh\:mm') formated_date
from (values
(cast('2020-03-12 16:20:34.000' as datetime)),
(cast('2020-01-01 00:52:34.000' as datetime))
) as t(contactdate)
contactdate | formated_date
:---------------------- | :--------------
2020-03-12 16:20:34.000 | Thursday 04:20
2020-01-01 00:52:34.000 | Wednesday 12:52

Related

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

How do I subtract two columns with datetime in SQLite?

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 |

Turning week number into week commencing in SSRS/SQL Server

I have a report that is grouped on week number but for presentation reasons want it to be week commencing.
Select
datepart(wk,[rhStartTime]) as [week number]
...
group by datepart(wk,[rhStartTime]),[rhOperatorName])
where
[week number] >= #StartWeek
and [week number] <= #EndWeek
My report parameters use week number to filter the data with #StartWeek and #EndWeek being integers that plug into the SQL. My question is one of presentation. It is tough for users to understand what Week 15 means in context so I would like to alter my output to show Week Commencing rather than week number but for the backend to still use weeknumber. I also don't want users to be able to pick any date because they will invariably pick dates that span multiple weeks without a full weeks data.
I look at similar questions and one here
SO question
recommended SQL of the format
DATEADD(dd, -(DATEPART(dw, WeddingDate)-1), WeddingDate) [WeekStart]
But plugging my columns into that format gave me a bit of a mess. It didn't group how I was expecting.
SELECT
DATEADD(dd, -(datepart(wk,[rhStartTime]))-1), [rhStartTime])) as [week commencing]
,datepart(wk,[rhStartTime])) as [week number]
...
group by datepart(wk,[rhStartTime])),DATEADD(dd, -(datepart(wk,[rhStartTime]))-1), [rhStartTime])),[rhoperatorname]
I got this output
where I was looking for all those week 15s to be grouped together with just one week commencing date.
Try This will work.This retrieves the dates eliminating time part of it
SELECT
Dateadd(dd,-(datepart(wk,convert( varchar(10),[rhStart Time],120))-1), convert( varchar(10),[rhStart Time],120))
,datepart(wk,[rhStart Time])) as [week number]
...
from Table X
group by Dateadd(dd,-(datepart(wk,convert( varchar(10),[rhStart Time],120))-1), convert( varchar(10),[rhStart Time],120))
,datepart(wk,[rhStart Time]))
,[Agent Name]
I think your problem is in how you are using the examples you have seen elsewhere and not with the examples themselves, as I have just tested the logic and it seems to be working for me without issue, as you can see in the script below.
I think your main problem is that you are not removing the time portion of your StartTime values, which you will need to do if you want to group all values that occur on the same day. The easiest way to do this is to simply cast or convert the values to date data types:
select cast(StartTime as date) as CastToDate
,convert(date, StartTime, 103) as ConvertToDate -- You may need to use 101 depending on your server setting for dd/mm/yyyy or mm/dd/yyyy
Script:
declare #StartDate date = '20170325'
,#EndDate date = '20170403';
-- Tally table to create dates to use in functions:
with n(n) as(select n from (values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n(n))
,d(d) as(select top(datediff(d,#StartDate,#EndDate)+1) dateadd(d,row_number() over (order by (select null))-1,#StartDate) from n n1,n n2,n n3,n n4,n n5,n n6)
select d
,datepart(week,d) as WeekNumber
,DATEADD(dd, -(DATEPART(dw, d)-1), d) as WeekCommencing
from d
order by d;
Output:
+------------+------------+----------------+
| d | WeekNumber | WeekCommencing |
+------------+------------+----------------+
| 2017-03-25 | 12 | 2017-03-19 |
| 2017-03-26 | 13 | 2017-03-26 |
| 2017-03-27 | 13 | 2017-03-26 |
| 2017-03-28 | 13 | 2017-03-26 |
| 2017-03-29 | 13 | 2017-03-26 |
| 2017-03-30 | 13 | 2017-03-26 |
| 2017-03-31 | 13 | 2017-03-26 |
| 2017-04-01 | 13 | 2017-03-26 |
| 2017-04-02 | 14 | 2017-04-02 |
| 2017-04-03 | 14 | 2017-04-02 |
+------------+------------+----------------+
Replace the field value in your SQL code with the expression below to remove time
DATEADD(dd, -(DATEPART(dw,[rhStartTime]) -1), DATEDIFF(dd, 0, [rhStartTime]) )
You can also achieve the same result by using the expression below in SSRS (change it to match your date field)
= DATEADD("d", - DATEPART(DateInterval.Weekday,Fields!rhStartTime.Value) +1,Fields!rhStartTime.Value)
Thanks for the answers. I'm sure they probably would have worked if I were more competent. In the end I created a simple table on my server with year,weeknumber,commencedate as the column headings and manually created them in excel. Then I linked my results as a cte to that table where year = 2017 and cte.weeknumber = commencedate.weeknumber It seems to have worked.
Now in my SSRS report parameter I am using weeknumber as the value and commence date as the label. So I don't have to change any of the other configuration.

Cast(GetDate() as int) comes out incorrect after noon

So is this supposed to happen? or is something wrong with my query.
if I run the following query
select getdate() as [Date],
CAST(getdate() as date) as [Time],
CAST(getdate() as INT) as INT,
Cast(CAST(cast(getdate() as int) as DATETime) as Date) as finish
If I run this at 11:55:00 AM [finish] returns the correct date.
If I run the query at 12:10:00 PM [finish] returns tomorrows date.
I tried to search for this and couldn't find anything so sorry if its been noted before.
I'm trying to group by Date but I don't want to group by time also, that is why I am doing the conversions.
Running Microsoft SQL Server 2008 R2
I think your problem is that (if you absolutely have to do these converts, I know it used to be required long ago) that you are using int instead of float and getting rounding on your converted values:
select getdate() as [Date]
,CAST(getdate() as date) as [Time]
,CAST(getdate() as INT) as INT
,Cast(CAST(cast(getdate() as int) as DATETime) as Date) as finishInt
,CAST(getdate() as float) as FLOAT
,Cast(CAST(cast(getdate() as float) as DATETime) as Date) as finishFloat
Output:
+-------------------------+------------+-------+------------+------------------+-------------+
| Date | Time | INT | finishInt | FLOAT | finishFloat |
+-------------------------+------------+-------+------------+------------------+-------------+
| 2017-02-07 16:47:59.823 | 2017-02-07 | 42772 | 2017-02-08 | 42771.6999979552 | 2017-02-07 |
+-------------------------+------------+-------+------------+------------------+-------------+

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.