I want to know how to get the exact hours between two dates in SQL Server.
I have two queries, but I am not getting the time I want; can you guys help me with this problem? The first one is this:
SELECT p.Id, p.FechaInicio, p.FechaFin,
DATEDIFF(MINUTE, p.FechaInicio, p.FechaFin) / 60 AS 'Duracion'
FROM Programaciones p
INNER JOIN Usuarios u ON u.Id = p.Programacion_Usuario
WHERE u.Nombre = 'User 1'
ORDER BY p.FechaCreacion DESC
This is the result:
And the second one is this:
SELECT p.Id, p.FechaInicio, p.FechaFin,
DATEDIFF(MINUTE, p.FechaInicio, p.FechaFin) / 60.0 as 'Duracion'
FROM Programaciones p
INNER JOIN Usuarios u ON u.Id = p.Programacion_Usuario
WHERE u.Nombre = 'User 1'
ORDER BY p.FechaCreacion DESC
result:
How can I transform 0.500000 to 0.5?
Thanks if you can help me. Have a good day.
You can cast your number as DECIMAL() to define how many decimal places you want to preserve:
CAST(DATEDIFF(MINUTE, p.FechaInicio, p.FechaFin) / 60.0 AS DECIMAL(5,1)) as 'Duracion' from Programaciones
The first parameter in DECIMAL() is the number of digits in total, the second is how many digits after the decimal point, in the case above, 5 digits total, 1 after the decimal point.
You could also wrap it in ROUND().
Related
I am trying to make a Calculation where I want to update ideal hours based on number of Assistant and Head Coaches based on whether a restaurant is 5 day or 7 day a week. When I make a calculation where I use 10/7 or 20/7, it takes it as 1 and 2 respectively. I am currently using trunc but I have tried using cast :: decimal(10,6) etc and it doesn't work.
select
a.entity,
a.store_name,
a.order_date,
a.daily_ideal_hours,
a.daily_ideal_hours - (case when b.days_open like '%Weekdays%' then ((c.total_acs*(20/5) + c.total_hcs*(10/5)))
when b.days_open like '%All%' then ((c.total_acs * trunc(20/7,10)) + (c.total_hcs * trunc(10/7,10))) end) as updated_value
from scorecards_ideal_labor_hours as a
left join days_store_open as b
on a.entity = b.entity
left join hc_ac_data as c
on a.entity = c.entity_id
and a.order_date = c.report_date
where a.order_date between '2021-12-06' and '2021-12-12'
and a.entity = 66
order by a.order_date desc;
How do I fix this?
You don't need to use trunc function here.
Just typecast both numerator and denominator to float.
This will give the final answer with decimal places, without any rounding:
select (10::float)/(7::float);
This gives answer as:
1.4285714285714286
If you need to round the final answer to few digits only:
select trunc((10::float)/(7::float),2);
I currently have a query running to average survey scores for agents. We use the date range of the LastDayOfTheQuarter and 180 days back to calculate these scores. I ran into an issue for this current quarter.
One of my agents hasn't received any surveys in 2020 which is causing the query to not pull the current lastdayofquarter and 180 days back of results.
The code I am using:
SELECT
Agent,
U.Position,
U.BranchDescription,
(ADDDATE(LastDayOfQuarter, -180)) AS MinDate,
(LastDayOfQuarter) AS MaxDate,
COUNT(DISTINCT Response ID) as SurveyCount,
AVG(CASE WHEN Question ID = Q1_2 THEN Answer Value END) AS EngagedScore,
AVG(CASE WHEN Question ID = Q1_3 THEN Answer Value END) AS KnowledgableScore,
AVG(CASE WHEN Question ID = Q1_6 THEN Answer Value END) AS ValuedScore
FROM qualtrics_responses
LEFT JOIN date D
ON (D.`Date`) = (DATE(`End Date`))
LEFT JOIN `users` U
ON U.`UserID` = `Agent ID`
WHERE `Agent` IS NOT NULL
AND DATE(`End Date`) <= (`LastDayOfQuarter`)
AND DATE(`End Date`) >= (ADDDATE(`LastDayOfQuarter`, -180))
GROUP BY `Agent`, (ADDDATE(`LastDayOfQuarter`, -180))
i know the issue is due to the way I am joining the dates and since he doesn't have a result in this current year, the end date to date join isn't grabbing the desired date range. I can't seem to come up with any alternatives. Any help is appreciated.
I make the assumption that table date in your query is a calendar table, that stores the starts and ends of the quarters (most likely with one row per date in the quarter).
If so, you can solve this problem by rearranging the joins: first cross join the users and the calendar table to generate all possible combinations, then bring in the surveys table with a left join:
SELECT
U.UserID,
U.Position,
U.BranchDescription,
D.LastDayOfQuarter - interval 180 day AS MinDate,
D.LastDayOfQuarter AS MaxDate,
COUNT(DISTINCT Q.ResponseID) as SurveyCount,
AVG(CASE WHEN Q.QuestionID = 'Q1_2' THEN Q.Answer Value END) AS EngagedScore,
AVG(CASE WHEN Q.QuestionID = 'Q1_3' THEN Q.Answer Value END) AS KnowledgableScore,
AVG(CASE WHEN Q.QuestionID = 'Q1_6' THEN Q.Answer Value END) AS ValuedScore
FROM date D
CROSS JOIN users U
LEFT JOIN qualtrics_responses Q
ON Q.EndDate >= D.Date
AND Q.EndDate < D.Date + interval 1 day
AND U.UserID = Q.AgentID
AND Q.Agent IS NOT NULL
GROUP BY
U.UserID,
U.Position,
U.BranchDescription,
D.LastDayOfQuarter
Notes:
I adapted the date arithmetics - this assumes that you are using MySQL, as the syntax of the query suggests
You should really qualify all the columns in the query, by prefixing them with the alias of the table they belong to; this makes the query so much easier to understand. I gave a tried at it, you might need to review that.
All non-aggregated columns should appear in the group by clause (also see the comment from Eric); this is a a requirement in most databaseses, and good practice anywhere
I am trying to get a percentage of number of times a product is faulty.
I have the faults in one table and the throughput in another. Throughput could never be 0. The report would never be ran if it was 0.
Unfortunately the tables cannot be joined.
I can get the correct result returned in SQL but when I apply the query to manufacturing software with date parameters applied I receive the divide by 0 error.
Query working in SQL:
SELECT
CAST (COUNT (faulttype.faults) AS FLOAT)/
CAST ((SELECT COUNT(throughput.throughput)
FROM [throughput]
WHERE throughput.throughput >= '2017-08-08 00:00:00' and throughput.throughput <= '2018-08-13 23:59:00')
AS FLOAT)
*100 Percentage
FROM faults (nolock)
INNER JOIN faulttype (nolock) ON faults = faults.faults
where fault.procedure = 15
and faults.regtime >= '2017-08-08 00:00:00' and qc_inspections.regtime <= '2018-08-13 23:59:00'
Query with date parameters applied (receives divide by 0 error):
SELECT
CAST (COUNT (faulttype.fault) AS FLOAT)/
CAST ((SELECT COUNT(throughput.throughput)
FROM [throughput]
WHERE CAST(faultype.regtime as date) between #datetimerange_From and #datetimerange_To
AS FLOAT)
*100 Percentage
FROM faults (nolock)
INNER JOIN faulttype (nolock) ON faults.id = faulttype.fault
where fault.procedure = 15
and CAST(faults.regtime as date) between #datetimerange_From and #datetimerange_To
I have tried nullif and also case statement to no avail. Case statement didn't work because of lack of join. I managed to fudge something together so that the case statement searched for an ID count of 1 then show one (that it would never be) else perform my division. I thought it would trick SQL into not seeing a 0 prior to the user applying the date parameters. Buuuut that didn't work and I am sure somebody will tell me why lol.
Its Strange you dont have join on [throughput]
table, but if i take your query like it, try Something like this:
with CountFault as (
select count(throughput) CountFault
from [throughput]
where CAST(throughput as date) between #datetimerange_From and #datetimerange_To
)
select count(f2.fault as decimal) / nullif(f3.CountFault, 0) * 100
from faults f1
INNER JOIN faulttype f2 ON f1.id = f2.fault
cross join CountFault f3
where f1.procedure = 15 and CAST(f1.regtime as date) between #datetimerange_From and #datetimerange_To
I'm trying to create a system that will select the old users that have not logged in for the past 7 days. I have a problem with this query.
The query should select the a.email, p.name, a.name, b.account_id, and I'll explain.
a is accounts
b is billing
p is players
Should check if the b.account_id is equal a.id that can get by p.account_id and after that should check if the p.lastlogin is higher or equal than 7 days then should return the query results.
I tried this, but it isn't working:
SELECT
`p`.`name`,
`a`.`email`,
`a`.`name`,
`b`.`account_id`
FROM
`billing` AS `b` AND `players` AS `p`
LEFT JOIN `accounts` AS `a`
ON `a`.`id` = `p`.`account_id` AND `a`.`name` = `b`.`account_id`
WHERE `p`.`lastlogin` >= UNIX_TIMESTAMP() + (7 * 86400)
AND group_id = 1
ORDER BY lastlogin
DESC
I hope that this is understandable, xD.
Regards,
vankk.
I think the problem is here.
WHERE `p`.`lastlogin` >= UNIX_TIMESTAMP() + (7 * 86400)
It should be -instead of +.
Also, why don't you use 2 JOINs?
You can also use the DATEDIFF function if you are using SQL
where DATEDIFF(d, a.DateValue , DateTimeNow) <7;
https://www.w3schools.com/sql/func_datediff.asp
I'm pretty new to sql and have been set a task of creating a query which will give me the first and last entrance of each user and how long they were in the office for.
So far i have got the below
SELECT
CONVERT(VARCHAR(10),evts.Eventtime,101) as Date,
CONVERT(VARCHAR(10),evts.Eventtime,108) as Time,
un.UserName AS [User],
case
when p.Name = 'ACU:4321104 - 5th floor (In)' then '5th entrance'
when p.name = 'ACU:4321176 - 4th floor (In)' then '4th entrance'
when p.name = 'ACU:4321176 - 4th floor (Out)' then '4th exit'
when p.name = 'ACU:4321104 - 5th floor (Out)' then '5th exit'
when p.name = 'ACU:4321158 - 3rd Floor (In)' then '3rd entrance'
when p.name = 'ACU:4321158 - 3rd Floor (Out)' then '3rd exit'
end as [where]
FROM
Net2Events.dbo.Events AS evts LEFT OUTER JOIN
dbo.vw_UserNamesFS AS un ON evts.UserID = un.UserID LEFT OUTER JOIN
Net2Events.dbo.[Event subtype description] AS esd ON evts.EventSubType = esd.EventSubType LEFT OUTER JOIN
Net2Events.dbo.[Event description] AS ed ON evts.EventType = ed.EventType LEFT OUTER JOIN
dbo.Peripherals AS p ON evts.Address = p.Address AND evts.SubAddr = p.SubAddr
WHERE evts.EventTime >= dateadd(day,datediff(day,1,GETDATE()),0)
AND evts.EventTime < dateadd(day,datediff(day,0,GETDATE()),0)
Which gives access to every entrance and exit. Any help would be highly appreciated.
Thanks
You will almost certainly need to adjust your where clause if this is more than a one off report, but for all EventTimes between those two dates, this query will give you the first and last EventTime by each user and the time between those in minutes.
If you need to further break this down by specific flors, you can add your where field back in (Though I would recommend against that name, as it is a SQL keyword) to both the select and the group by:
SELECT un.UserName AS [User]
,MIN(evts.Eventtime) as FirstEvent
,MAX(evts.Eventtime) as LastEvent
,DATEDIFF(minute,MIN(evts.Eventtime),MAX(evts.Eventtime)) as TimeDifference
FROM Net2Events.dbo.Events AS evts
LEFT OUTER JOIN dbo.vw_UserNamesFS AS un
ON evts.UserID = un.UserID
LEFT OUTER JOIN Net2Events.dbo.[Event subtype description] AS esd
ON evts.EventSubType = esd.EventSubType
LEFT OUTER JOIN Net2Events.dbo.[Event description] AS ed
ON evts.EventType = ed.EventType
LEFT OUTER JOIN dbo.Peripherals AS p
ON evts.Address = p.Address
AND evts.SubAddr = p.SubAddr
WHERE evts.EventTime >= dateadd(day,datediff(day,1,GETDATE()),0)
AND evts.EventTime < dateadd(day,datediff(day,0,GETDATE()),0)
GROUP BY un.UserName
I think you will need to do more than just the first and last event however, as I don't think there is a production database in the world with 100% correct data. This means you will need to find the earliest In event and the latest Out event and then check that these make sense.
You can 'exclude' certain rows from aggregates like min and max with a case statement that substitutes an impossible value way beyond the normal range which you can handle if needs be later on:
min(case when <criteria to include> then EventTime else '29990101' end)
Edit to add in response to comment
To format your Time Difference into various date elements, you need to start with your largest date part - ie: Days? Hours? - and then work down from there. Start with working out how many full days you have, which for a value in minutes means doing integer division by 60 to get the number of full hours and then by 24 to get the number of full days:
#difference / 60 / 24
We then need the number of full hours, minus all the hours taken up in the full days. To do this we can do the above calculation by use modulo instead of division to find the remainder of the hours that don't create a full day:
#difference / 60 % 24
And then to find the number of minutes left over, we simply need to find the remainder of a division by 60:
#difference % 60
Do some cast/converting to get the right formatting and you have your difference in Days, Hours and Minutes:
declare #start datetime = getdate() - 400.255;
declare #end datetime = getdate();
declare #difference int = datediff(minute,#start,#end);
select cast(#difference/60/24 as nvarchar(5)) + case when #difference/60/24 = 1 then ' Day, ' else ' Days, ' end
+ cast(#difference/60%24 as nvarchar(5)) + case when #difference/60%24 = 1 then ' Hour, ' else ' Hours, ' end
+ cast(#difference%60 as nvarchar(5)) + case when #difference%60 = 1 then ' Minute' else ' Minutes' end;
which returns: 400 Days, 6 Hours, 7 Minutes
Of course, if you only ever want Hours and Minutes in hh:mm format and are super confident this time difference will never go over 23 hours, 59 minutes and 59.9999999 seconds, you can simply convert the difference to a time value by adding it to an arbitrary date, and formatting accordingly in your front end application:
cast(dateadd(minute,#difference,0) as time)
Which returns: 06:07:00.0000000 for the parameters above - Note the missing 400 days.