How to use stored procedure to calculate DateTime difference in hours? - sql-server

I have two tables, TicketReport and TimeTracker.
TicketReport Columns:
Ticket_Number
Report_DT (DateTime ticket was reported)
Response_Time (Hourly value. How long it took for this ticket to be responded to. This is where I need the place the hours. DateTime Reported minus DateTime started)
TimeTracker Column:
Ticket_Number
Time_Start( DateTime that work started on this ticket)
Right now, for every row in my TicketReport table, the Response_Time column contains either Null or just a test value of 1(hour).
*I need to calculate how many hours it took for a ticket to be responded to (ReportDT - Time_Start), and then insert that hourly value into the Report_DT column for each row in the TicketReport table.
I did some research and found DATEDIFF, but I think this only returns days, and even if it did return hours, im not sure how to use it.
How could I accomplish this in a stored procedure?

To update the response_time column with the number of hours you can use a simple update query (which you could wrap in a stored proc if you need.
The query could look like this:
-- uncomment the next line to create a sp...
-- create proc update_response_time as
update tr
set response_time = datediff(hour, report_dt, time_start)
from TicketReport tr
join TimeTracker tt on tr.Ticket_Number = tt.Ticket_Number
If you want to run it without updating (to see what the values would be) you can run it as a select query:
select *, datediff(hour, report_dt, time_start) as diff_in_hours
from TicketReport tr
join TimeTracker tt on tr.Ticket_Number = tt.Ticket_Number
Be aware that these queries assume that there are just one matching row in the TimeTracker table for each ticket. If there can be multiple rows you would need another solution. Also know that the hour value doesn't take minutes into account at all so if report_dt is at 12:00 and time_start is at 12:30 it would be reported as 0 hours, so maybe a finer granularity than hours would be more suitable.

You can use DATEDIFF function
Syntax
DATEDIFF ( datepart , startdate , enddate )
pass datepart hh to get hours

Related

i can not understand why a query filtering on datetime field is not working on sql server 2016

This is a very basic query:
select * from [dbo].[TestTable] where year(start_date)>2021
it returns no records, start_date is datetime, the table contains many records with that field valorized and dates beyound 2021.
this query return all the records of the table:
SELECT year(start_date), * FROM [dbo].[TestTable] order by start_date desc
this the table structure:
another query with strange result:
SELECT year(start_date), case when year(start_date)>2021 then 1 else 0 end, * FROM [ADS].[dbo].[TestTable] order by start_date desc
what can i check?
You are missing the = part of the operator. All the rows seem to have 2021-01-01, so the YEAR is not greater than 2021, it IS 2021.
You'd need to either do
select * from [dbo].[TestTable] where year(start_date)>=2021
or
select * from [dbo].[TestTable] where year(start_date)=2021
As Dan Guzman points out, as an additional improvement, you should avoid using functions on your WHERE clauses because that will prevent the use of indexes, since it requires to execute the function against every single row on the table to be able to determine if it's a match.
If it's a small table in terms of record count, it's not a big deal, but if you're talking about tens of thousands or more, it will add up.
The alternatives would be to either filter by the original date value, or save the year as a separate field and add an index to it.
It's working fine. None of the results in the picture contains record where year(start_date)>2021.
So I think you might looking for the rows where start date is greater than 2020
select * from [dbo].[TestTable] where year(start_date)>2020
OR
select * from [dbo].[TestTable] where year(start_date)>=2021
Or as #Dan Guzman suggested it would be better to use:
select * from [dbo].[TestTable] where start_date>='2021-01-01'
Nothing in that table has a year > 2021. There dates greater then the start of the year, but when looking at just the years, they are equal to 2021, not greater.
To fix this, I'd remove the year() function completely. Calling a function on a column can be bad for performance, because it impacts the ability to use indexes on the column. This one is probably not awful (year() is deterministic, and so sometimes the index is still okay), but if there is a way to express a query without the function it's usually a good idea. In this case, we can do it like this:
select * from [dbo].[TestTable] where start_date >= '20210101'

Date range based on Column Date

I am using the latest SQL Server. I have a table with a CreatedDate column. I need to write a Query that uses dates that are plus or minus 7 from the Date in CreatedDate. I have no clue how to go about this. My thought was this:
DECLARE #Date datetime
DECLARE #SevenBefore datetime
DECLARE #SevenAfter datetime
SET #Date = CreatedDate
SET #SevenBefore = DATEADD(day,-7,#Date)
SET #SevenAfter = DATEADD(day,7,#Date)
SELECT *
FROM <table>
WHERE <table> BETWEEN #SevenBefore AND #SevenAfter
The issue with this is that I cannot use "CreatedDate" as a SET #DATE because SQL gives an error "Invalid column name 'CreatedDate'"
Any help would be appreciated. I cannot list a date because every date in that column could be different.
Thanks
In this case, you need to stop thinking as a programmer would, and start thinking as a Database programmer would.
Lets work only with this central part of your query:
SELECT *
FROM <table>
WHERE <table> BETWEEN #SevenBefore AND #SevenAfter
Now, you say that the CreatedDate is a column in a table. For this example, I will assume that the CreatedDate is in a table other than the one in your example above. For this purpose, I will give two fake names to the tables. The table with the CreatedDate, I will call tblCreated, and the one from the query above I will call tblData.
Looking above, it's pretty obvious that you can't compare an entire table row to a date. There must be a field in that table that contains a date/time value. I will call this column TargetDate.
Given these assumptions, your query would look something like:
SELECT *
FROM tblCreated tc
INNER JOIN tblData td
ON td.TargetDate BETWEEN DATEADD(day, -7, tc.CreatedDate) and DATEADD(day, 7, tc.CreatedDate)
Looking at this, it is clear that you still need some other associations between the tables. Do you only want all data rows per customer based on the Created date, or perhaps only want Creations where some work was done on them as shown in the Data records, or ??. Without a fuller specification, we can't help with that, though.

SQL update based on query results with two parameters

I've created a virtual table in SQL Server that has 28 days from the current date and each date has rows for time that range from 12-10 pm incremented by 15 min and another value to indicate that it's turned on/off for availability, so it would be something like this:
date time onoff
-------------------------------------------------
2015-04-08 12:00 1
2015-04-08 12:15 1
....continue until 22:00 then start next day
2015-04-09 12:00 1
..... continue for 28 days
I'd like to update the availability based on a query from another table which would return the date, start and end time...
So far I came up with this
update table1
set onoff = 0
where tbl1date in (select tbl2date from table2 where userid = 1)
The problem I'm having is adding in the between certain hours part of the equation and I'm not sure how to do something like this in SQL or how to even search for the answer based on not being able to word it properly...
Can someone help or point me in the right direction?
use a DATETIME, don't use separate DATE and TIME fields.
I think you should take a look at DATEDIFF (https://technet.microsoft.com/pl-pl/library/ms189794(v=sql.110).aspx) function.
Your where query could look like this:
update table1 set onoff = 0
where
DATEDIFF(minute, <MIN_RANGE>, tbl1date) >= 0 and
DATEDIFF(minute, tbl1date, <MAX_RANGE>) >= 0
How you calculate MIN_RANGE and MAX_RANGE depends on your table2 structure.
As suggested, if you have control over the structure, use datetime fields as they are easier to do the comparisons on. I'm going to assume you don't have control over the structure.
In order to compare the datetimes you need to create them from your separate date and times. You can either parse the time field for the hours and minutes and use DATEADD to add the appropriate offsets to the date, or you can use CONVERT to interpret a date time string as a date. Something like
CONVERT(datetime, SUBSTRING(CONVERT(varchar, tbl1date, 121), 1, 10) + ' ' + tbl1time, 121)
What this does is to convert the date to odbc cannonical format and throwaway the time part as it takes only the first 10 characters. Then it appends the time and interprets the whole string as a odbc cannonical datetime string. That format is yyyy-mm-dd hh:mi:ss.mmm. The hours are based on 24 hours. So if your times are in AM/PM format you're going to have to convert them.
If your other table has separate date and times you'd use a similar expression to combine them.
Once you have the datetimes you can do something like this
UPDATE table1
SET onoff = 0
WHERE <expression above> BETWEEN (SELECT min_value FROM table2) AND (SELECT max_value FROM table2)

How to Get rows that are added 'x' minutes before in sqlserver?

I want to get all rows that have being added 'x' minutes before.
SELECT [PromoCodeID]
,[CustomerID]
,[DiscountAmount]
,[AddedBy]
,[AddedDate]
,[ModifiedBy]
,[ModifiedDate]
FROM [tbl_PromoCodesNewCustomer]
Where....
Eg: Records added 30min before from todays date time
NOTE: Record Added date is added in the field 'AddedDate' which has DATETIME datatype.
You can use this:
SELECT [PromoCodeID]
,[CustomerID]
,[DiscountAmount]
,[AddedBy]
,[AddedDate] AS added
,[ModifiedBy]
,[ModifiedDate]
FROM [tbl_PromoCodesNewCustomer]
WHERE DATEADD(minute,x,added) > GETDATE()
Where "x" in DATEADD is the number of minutes you want.
i suggest a light variation on FirstHorizon answer:
SELECT [PromoCodeID]
,[CustomerID]
,[DiscountAmount]
,[AddedBy]
,[AddedDate] AS added
,[ModifiedBy]
,[ModifiedDate]
FROM [tbl_PromoCodesNewCustomer]
WHERE AddedDate < DATEADD(minute * -1,x,getdate())
the change may look minor but depending on the number of involved rows, indexes and some other factor evaluated by the query optimizer this query may perform way better because there is no calc to make on the data.
here is an article that explain the reason (look at the second paragraph, 'Using Functions in Comparisons within the ON or WHERE Clause').
EDIT:
I'd advise you to populate the addedDate field with the UTC date and time, otherwise you could have problems with data managed among different servers \ time zones or on time change days.
So, if we consider this, the where clause will be:
WHERE DATEDIFF(mi,addedDate,GETUTCDATE)<30

Question about Crystal Reports + SQL Server stored procedure with GROUP BY

I'm writing a report in Crystal Reports XI Developer that runs a stored procedure in a SQL Server 2005 database. The record set returns a summary from log table grouped by Day and Hour.
Currently my query looks something like this:
SELECT
sum(colA) as "Total 1",
day(convert(smalldatetime, convert(float, Timestamp) / 1440 - 1)) as "Date",
datepart(hh, convert(smalldatetime, convert(float, Timestamp) / 1440 - 1)) as "Hour"
`etc...`
GROUP BY
Day, Hour
Ignore the date insanity, I think the system designers were drinking heavily when they worked out how to store their dates.
My problem is this: since there are not always records from each hour of the day, then I end up with gaps, which is understandable, but I'd like Crystal to be able to report on the entire 24 hours regardless of whether there is data or not.
I know I can change this by putting the entire query in a WHILE loop (within the stored procedure) and doing queries on the individual hours, but something inside me says that one query is better than 24.
I'd like to know if there's a way to have Crystal iterate through the hours of the day as opposed to iterating through the rows in the table as it normally does.
Alternatively, is there a way to format the query so that it includes the empty hour rows without killing my database server?
Here's how I solved this problem:
Create a local table in your SQL-Server. Call it "LU_Hours".
This table will have 1 integer field (called "Hours") with 24 rows. Of course, the values would be 1 through 24.
Right join this onto your existing query.
You might need to tweak this to make sure the nulls of empty hours are handled to your satisfaction.
You could use a WITH clause to create the 24 hours, then OUTER JOIN it.
WITH hours AS (
SELECT 1 AS hour
UNION
SELECT 2 AS hour
...
SELECT 24 AS hour
)
SELECT *
FROM hours h
LEFT OUTER JOIN [your table] x ON h.hour=x.datepart(hh, convert(smalldatetime, convert(float, Timestamp) / 1440 - 1))
This SQL would need to added to a Command.
Group as necessary in the SQL or the report.

Resources