Going more than 24hrs and adding days - sql

I have an expression in a table that is calculating the total of the column that has different times in it. But after the total goes over 24 hours it resets. I want to add to have days also in it if it goes more than 24hrs. I have so far added days in the format but this means that even with 0 days it gives 01 days since it is using the days section of the date. This is wrong and I either want to take one away from this ot have some sort of a counter to count the days. This is the expression if have so far:
=format(DateAdd("s", SUM(Fields!TotalDowntime.Value), "00:00:00"), "dd 'days' HH 'hrs' mm 'mins' ss 'secs'")
I have tried to format and using dateadd function to see if this can be done in a different way

The following isn't a full answer, but I'm hoping it will help you towards one. I think I've understood from your question that the field which records your TotalDowntime figure records this value in seconds.
SELECT
TotalDowntime/(24*60*60) as [days],
TotalDowntime/(60*60) % 24 as [hours],
TotalDowntime/(60) % 60 as [minutes],
TotalDowntime % 60 as [seconds]
FROM
MyTable
You'll see that all the parts simply cut off any decimals that result from the division. The % is SQL Servers "Mod" function that returns the remainder on division.
You should be able to put code similar to the above "server side" and concatenate these columns in reportbuilder (or server side if you wish).

Related

Calculate the only necessary difference and Group by between two Timestamps in PostgreSQL

I see similar question but didn't find helpful answer for my problem.
I have one query:
select au.username
,ej.id as "job_id"
,max(ec."timestamp") as "last_commit"
,min(ec."timestamp") as "first_commit"
,age(max(ec."timestamp"), min(ec."timestamp")) as "diff as age"
,to_char(age(max(ec."timestamp")::timestamp, min(ec."timestamp")::timestamp),'HH:MI:SS') as "diff as char"
,et.id as "task_id"
from table and etc..
And that my output(Sorry for picture but its best view):
So, as you can see I have timestamp with zones, and I trying calculate difference between last_commit and first_commit. Within function age its goes well, but I need extract only hours and minutes from this subtraction. N.B! only hours and minutes not days for example job_id=1 first row, the difference is 2 minutes and 42 seconds and where job_id=2 second row, the difference is 2 hours and 2 minutes and 55 sec, not 16 days X 24 hours, I don't need calculate days. When I try to_char its return not exactly what I expect. Last two columns within green color in my picture, show what I expect and want. So for every row calculate difference between last and first commit included only hours and minutes (in other words calculate only time not dates) and calculate total sum by task_id as represent in last column in pic.
Thanks.
try this :
SELECT age(max(ec."timestamp"), min(ec."timestamp")) - date_trunc('day', age(max(ec."timestamp"), min(ec."timestamp")))
You can try converting a Timestamp type to just time, like in this answer.
The result of string SQL is:
select au.username
,ej.id as "job_id"
,max(ec."timestamp") as "last_commit"
,min(ec."timestamp") as "first_commit"
,(max(ec."timestamp")::time-min(ec."timestamp")::time) as "diff as age"
,to_char(age(max(ec."timestamp")::timestamp, min(ec."timestamp")::timestamp),'HH:MI:SS') as "diff as char"
,et.id as "task_id"
There are otres possible solutions working with timestamp, but this one i consider simple.

Why is the result of datediff year in Firebird too high?

I have question about function datediff in firebird. When I try to diff two dates like 15.12.1999 and 30.06.2000 in sql like this
SELECT
SUM(datediff (YEAR, W.FROM, W.TO)),
SUM(datediff (MONTH, W.FROM, W.TO)),
SUM(datediff (DAY, W.FROM, W.TO))
FROM WORKERS W
WHEN W.ID=1
I get in result 1 year, 6 month and 198 days but it is not true with value years (of course result should be 0) How I have to write my query to get correct result in parameter year? In that link https://firebirdsql.org/refdocs/langrefupd21-intfunc-datediff.html in documentation there is information about this case but there is not how to solve this problem.
The documentation is not very clear, but I'm pretty sure that datediff() is counting the number of boundaries between two dates. (This is how the very similar function in SQL Server works.) Hence, for year, it is counting the number of "Dec 31st/Jan 1st" boundaries. This is explicitly explained in the documentation.
If you want a more accurate count, you can use a smaller increment. The following is pretty close:
(datediff(day, w.from, t.to) / 365.25) as years_diff

SQL Average of total days in DATA per month

I have a SQL question.
I am trying to find the average injection volume per month. Currently my code takes the sum of all days of injection, and divides them by the TOTAL DAYS in the month.
Sum(W1."INJECTION_VOLUME" /
EXTRACT(DAY FROM LAST_DAY(W1."INJECTION_DATE"))) AS "AVGINJ"
This is not what I wanted.
I need to take the injection_volume and divide by the total days in the DATA .
ie. right now the data only 8 days of injection volume, lets say it is 3000.
So right now the sql is 3000/31.
I need to have it be 3000/8 (the total days in the data for the current month.)
Also, this should only be for the current month. All other completed months should be divided by the total days in the month.
Use
SELECT
SUM(W1.INJECTION_VOLUME) / COUNT(DISTINCT MyDateField)
FROM MyTable
WHERE X=Value
This gives you what you're after
SUM(W1.INJECTION_VOLUME) is the total volume for the dataset
Gives you the number of days, no matter how many records you have
COUNT(DISTINCT MyDateField)
So if you have 100 records but only 5 actual unique days in this time, this expression gives you 5
Note that this kind of calc is normally worked out with
SUM(A) / SUM(B)
not
SUM(A/B)
They give you completely different answers.
In order to get the average of the data for the current month you will need to divide by the count in the month:
SUM(`W1`.`INJECTION_VOLUME` / COUNT(EXTRACT(YEAR_MONTH FROM `W1`.`INJECTION_DATE`)))
To get all other data as the full month you'll need to combine your code:
SUM(`W1`.`INJECTION_VOLUME` / EXTRACT(DAY FROM LAST_DAY(`W1`.`INJECTION_DATE`)))
With an IF. So something like this:
SUM(
IF(
EXTRACT(YEAR_MONTH FROM `W1`.`INJECTION_DATE`) = EXTRACT(YEAR_MONTH FROM NOW()),
`W1`.`INJECTION_VOLUME` / COUNT(EXTRACT(YEAR_MONTH FROM `W1`.`INJECTION_DATE`)),
`W1`.`INJECTION_VOLUME` / EXTRACT(DAY FROM LAST_DAY(`W1`.`INJECTION_DATE`)
)
)
Note: this is untested and I'm not sure about the RDBMS you are using so you may need to change the code slightly to make it work.

SQL Server adding two time columns in a single table and putting result into a third column

I have a table containing two time columns like this:
Time1 Time2
07:34:33 08:22:44
I want to add the time in both these columns and put the result of addition into a third column may be Time3
Any help would be appreciated..Thanks
If the value you expect as the result is 15:57:17 then you can get it by calculating for instance the number of seconds from midnight for Time1 and add that value to Time2:
select dateadd(second,datediff(second,0,time1),time2) as Time3
from your_table
I'm not sure how meaningful adding two discrete time values together is though, unless they are meant to represent duration in which case the time datatype might not be the best as it is meant for time of day data and only has a range of 00:00:00.0000000 through 23:59:59.9999999 and an addition could overflow (and hence wrap around).
If the result you want isn't 15:57:17 then you should clarify the question and add the desired output.
The engine doesn't understand addition of two time values, because it thinks you can't add two times of day. You get:
Msg 8117, Level 16, State 1, Line 8
Operand data type time is invalid for add operator.
If these are elapsed times, not times of day, you could take them apart with DATEPART, but in SQL Server 2008 you will have to use a CONVERT to put the value back together, plus have all the gymnastics to do base 60 addition.
If you have the option, it would be best to store the time values as NUMERIC with a positive scale, where the unit of measure is hours, and then break them down when finally reporting them. Something like this:
DECLARE
#r NUMERIC(7, 5);
SET #r = 8.856;
SELECT FLOOR(#r) AS Hours, FLOOR(60 * (#r - FLOOR(#r))) AS Minutes, 60 * ((60 * #r) - FLOOR(60 * #r)) AS Seconds
Returns
Hours Minutes Seconds
8 51 21.60000
There is an advantage to writing a user-defined function to do this, to eliminate the repeated 60 * #r calculations.

Calculating the AVG value per GROUP in the GROUP BY Clause

I'm working on a query in SQL Server 2005 that looks at a table of recorded phone calls, groups them by the hour of the day, and computes the average wait time for each hour in the day.
I have a query that I think works, but I'm having trouble convincing myself it's right.
SELECT
DATEPART(HOUR, CallTime) AS Hour,
(AVG(calls.WaitDuration) / 60) AS WaitingTimesInMinutes
FROM (
SELECT
CallTime,
WaitDuration
FROM Calls
WHERE DATEADD(day, DATEDIFF(Day, 0, CallTime), 0) = DATEADD(day, DATEDIFF(Day, 0, GETDATE()), 0)
AND DATEPART(HOUR, CallTime) BETWEEN 6 AND 18
) AS calls
GROUP BY DATEPART(HOUR, CallTime)
ORDER BY DATEPART(HOUR, CallTime);
To clarify what I think is happening, this query looks at all calls made on the same day as today, and where the hour of the call is between 6 and 18 -- the times are recorded and SELECTed in 24-hour time, so this between hours is to get calls between 6am and 6pm.
Then, the outer query computes the average of the WaitDuration column (and converts seconds to minutes) and then groups each average by the hour.
What I'm uncertain of is this: Are the reported BY HOUR averages only for the calls made in that hour's timeframe? Or does it compute each reported average using all the calls made on the day and between the hours? I know the AVG function has a optional OVER/PARTITION clause, and it's been a while since I used the AVG group function. What I would like is that each result grouped by an hour shows ONLY the average wait time for that specific hour of the day.
Thanks for your time in this.
The grouping happens on the values that get spit out of datepart(hour, ...). You're already filtering on that value so you know they're going to range between 6 and 18. That's all that the grouping is going to see.
Now of course the datepart() function does what you're looking for in that it looks at the clock and gives the hour component of the time. If you want your group to coincide with HH:00:00 to HH:59:59.997 then you're in luck.
I've already noted in comments that you probably meant to filter your range from 6 to 17 and that your query will probably perform better if you change that and compare your raw CallTime value against a static range instead. Your reasoning looks correct to me. And because your reasoning is correct, you don't need the inner query (derived table) at all.
Also if WaitDuration is an integer then you're going to be doing decimal division in your output. You'd need to cast to decimal in that case or change the divisor a decimal value like 60.00.
Yes if you use the AVG function with a GROUP BY only the items in that group are averaged. Just like if you use the COUNT function with a GROUP BY only the items in that group are counted.
You can use windowing functions (OVER/PARTITION) to conceptually perform GROUP BYs on different criteria for a single function.
eg
AVG(zed) OVER (PARTITION BY DATEPART(YEAR, CallTime)) as YEAR_AVG
Are the reported BY HOUR averages only for the calls made in that hour's timeframe?
Yes. The WHERE clause is applied before the grouping and aggregation, so the aggregation will apply to all records that fit the WHERE clause and within each group.