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

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 |
+-------------------------+------------+-------+------------+------------------+-------------+

Related

SQL convert to week day and hh:mm

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

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

Raise Error/ Throw Exception for Certain Condition SQL Server

http://www.sqlfiddle.com/#!18/c913b/1
CREATE TABLE Table1 (
[ID] int PRIMARY KEY,
[Date] date,
[Name] varchar(40)
);
INSERT INTO Table1 (ID, date, Name )
Values ('1','07-20-18','Fred'),
('2','07-15-18','Sam'),
('3','07-20-18','Ben'),
('4','07-19-18','Simon'),
('5','07-25-18','Dave');
Current Query:
DECLARE #StartDate AS DATETIME,
#CurrentDate AS DATETIME
SET #StartDate = GETDATE() -30
SET #CurrentDate = GETDATE()
SELECT [ID], [Date], [Name]
FROM Table1
WHERE [Date] BETWEEN #StartDate AND #CurrentDate
Current result:
| ID | Date | Name |
|----|------------|-------|
| 1 | 2018-07-20 | Fred |
| 2 | 2018-07-15 | Sam |
| 3 | 2018-07-20 | Ben |
| 4 | 2018-07-19 | Simon |
This query compares with the range of day set for the #startdate variable. This can be changed to anything by anyone who wants to run the query. The issue is if someone selects a really large range of dates it crashes. Is there a way i can set an if statement that throws an error message if for example they tried to run a query for longer than 100 days.
Result: ERROR - Please lower the date range
Is this possible at all?

Create work pattern SQL table

I'm looking to create what appears to be quite a simple table in SQL, however, I'm struggling to create it.
The first date at which the work pattern starts is 01/01/1990 (UK date format: dd/mm/yyyy - happy to have this as 1990/01/01 if necessary). The end date of the first period is 8 weeks from the start date (26/02/1990). The start date of the next period is the day after the previous end date (27/02/1990) and so on. I'd want the last end date to be some time in the future (at least 10 years from now).
This is ideally how I want the table to look:
+--------+------------+------------+
| Period | Start Date | End Date |
+--------+------------+------------+
| 1 | 01/01/1990 | 26/02/1990 |
| 2 | 27/02/1990 | 24/04/1990 |
| 3 | 25/04/1990 | 20/06/1990 |
| 4 | 21/06/1990 | 16/08/1990 |
| 5 | 17/08/1990 | 12/10/1990 |
+--------+------------+------------+
Any help much appreciated.
If you are just adding 8 weeks and not considering the weekends you can follow something like this.
DECLARE #tempTable TABLE(
Period INT IDENTITY PRIMARY KEY,
StartDate DateTime,
EndDate DateTime
);
DECLARE #startDate DATETIME = GETDATE();
DECLARE #endDate DATETIME;
DECLARE #currYear INT = DATEPART(YY,#startDate);
DECLARE #endYear INT = #currYear + 10;
WHILE (#currYear <= #endYear)
BEGIN
SET #endDate = DATEADD(WEEK,8,#startDate);
INSERT INTO #tempTable (StartDate, EndDate) VALUES(#startDate, #endDate);
SET #startDate = DATEADD(dd,1,#endDate);
SET #currYear = DATEPART(YY,#startDate);
END;
SELECT Period, FORMAT(StartDate,'dd/MM/yyyy') AS StartDate, FORMAT(EndDate,'dd/MM/yyyy') AS EndDate FROM #tempTable
CREATE TABLE your_table
(
Period INT,
StartDate DATE,
EndDate DATE
)
INSERT INTO your_table
VALUES
(1,'1990-01-01','1990-02-26')
--etc

Sql Server - Comparing time only in 24 hour format?

I want to compare time with a time-range and if that particular time lies with-in that time-range, then it should return a record.
For example, Table 'A' has :
+-----------+------+-------------+-----------+
| User_Code | Name | Shift_Start | Shift_End |
+-----------+------+-------------+-----------+
| 1 | ABC | 04:01:00 | 11:00:00 |
| 2 | DEF | 11:01:00 | 20:00:00 |
| 3 | XYZ | 20:01:00 | 04:00:00 |
+-----------+------+-------------+-----------+
Now I want to check whose shift was it at this specific datetime : 2016-09-26 02:51:59. The SQL query should return the User_Code = 3. Shift_Start and Shift_End are of type time.
I have tried converting 2016-09-26 02:51:59 to time and then comparing with shift_start and shift_end using between and using logical operator but I am unable to get the desired result.
This has got me baffled. Its been an hour since I have tried coming up with a solution but I am unable to do so. Tried googling but got nothing there too. Any help will be appreciated. Using SQL Server 2012.
You need a more complicated where condition, because the shift times can be in either order.
So:
where ((shift_start < shift_end) and
cast(#datetime as time) between shift_start and shift_end)
) or
((shift_start > shift_end) and
cast(#datetime as time) not between shift_end and shift_start)
)
declare #t table(
User_Code int,
Name varchar(20),
Shift_Start time,
Shift_End time
);
insert #t(User_Code,Name,Shift_Start,Shift_End)
values
(1,'ABC','04:01:00','11:00:00')
,(2,'DEF','11:01:00','20:00:00')
,(3,'XYZ','20:01:00','04:00:00');
Try
declare #d datetime = '2016-09-26 02:51:59';
select *
from #t
cross apply ( -- intermediate vars: rounded param
select dt = cast(cast(#d as date) as datetime)
) r
where #d between dateadd(d, case when Shift_Start<Shift_End then 0 else -1 end, dt) + cast(Shift_start as datetime)
and dt+cast(Shift_end as datetime);
Approach from the other angle and add the date part of your search criteria to the Shift Start and End Times:
Note the case statement, this handles the situation where the shift end crosses midnight.
DECLARE #dateTime DATETIME = '2016-09-26 02:51:59'
-- Remove the time portion of above
DECLARE #datePortion DATETIME = DATEADD(dd, 0, DATEDIFF(dd, 0, #dateTime))
SELECT * FROM TableA
WHERE #dateTime BETWEEN #datePortion + cast(Shift_Start as datetime)
AND CASE WHEN ShiftEnd < ShiftStart
THEN DATEADD(day, 1, #datePortion)
ELSE #datePortion
END + cast(Shift_End as datetime)