I'm struggling with something that seems very obvious on first sight and most probably I'm overlooking something stupid but anyway.
I need to calculate the difference between timestamp fields and convert the result (which is as I assume a timestamp ) into the number of days and the elapsed time.
I can't seem to get the cast(xx to time) wright
I made a small example
SELECT
Cast(Cast( c_date AS CHAR(10)) || ' ' || Cast( c_time AS CHAR(10)) AS TIMESTAMP(6)) AS starttime ,
Cast(Cast( e_date AS CHAR(10)) || ' ' || Cast( e_time AS CHAR(10)) AS TIMESTAMP(6)) AS endtm,
(endtm - starttime) DAY(4) TO SECOND AS difftime
,Extract(DAY From difftime) --> gives the days
,Cast(difftime AS TIME)
,Extract (HOUR From difftime)
FROM (
SELECT Cast(Current_Timestamp AS DATE) c_date,
Cast(Current_Timestamp(0) AS TIME(0)) c_time,
Cast(Current_Timestamp + Random(1,10) * INTERVAL '1' DAY AS DATE) e_date,
Cast(Current_Timestamp(0) + Random(1,24) * INTERVAL '1' HOUR + Random(1,60) * INTERVAL '1' MINUTE AS TIME(0)) e_time
) t
,Cast(difftime AS TIME) gives me the trouble
the extract day and hour works => the difftime is really a timestamp (is it ? and if not what kind of field is it then ? ).
some advise would be nice :-)
Related
I'm looking for some help in Oracle SQL. I need to query date and time in the where clause to find shift data based on current date. There are 3 shifts, 5am to 1pm, 1pm to 9pm and 9pm to 5am(next day morning. For example
SELECT 'T1' AS SHIFT, WORK_CENTER, SUM(CASE WHEN AQL='PASS' THEN 1 ELSE 0) END AS AQL_PASSED
FROM Z_INSPECTION_DEFECTS
WHERE DATE_TIME >= TO_DATE((SELECT CONCAT(TO_CHAR(CURRENT_DATE, ''DD-MON-YYYY''), '' 5:00:00 '') FROM DUAL) , ''DD-MON-YYYY HH:MI:SS '') AND
DATE_TIME < TO_DATE((SELECT CONCAT(TO_CHAR(CURRENT_DATE, ''DD-MON-YYYY''), '' 1:00:00 '') FROM DUAL) , ''DD-MON-YYYY HH:MI:SS '')
I do not get any results from this query. The date time field is a timestamp on local Los Angeles time.
The immediate problem is that you're looking dor times that are after 5am and before 1am, which logically means nothing matches - as no time can fulfil both at once. You can use 24-hour times instead:
WHERE DATE_TIME >= TO_DATE((SELECT CONCAT(TO_CHAR(CURRENT_DATE, ''DD-MON-YYYY''), '' 5:00:00 '') FROM DUAL) , ''DD-MON-YYYY HH24:MI:SS '') AND
DATE_TIME < TO_DATE((SELECT CONCAT(TO_CHAR(CURRENT_DATE, ''DD-MON-YYYY''), ''13:00:00 '') FROM DUAL) , ''DD-MON-YYYY HH24:MI:SS '')
But there are other ways to get those, e.g. just without the queries against dual:
WHERE DATE_TIME >= TO_DATE(TO_CHAR(CURRENT_DATE, ''DD-MON-YYYY'') || '' 5:00:00 '', ''DD-MON-YYYY HH24:MI:SS '') AND
DATE_TIME < TO_DATE(TO_CHAR(CURRENT_DATE, ''DD-MON-YYYY'') || ''13:00:00 '', ''DD-MON-YYYY HH24:MI:SS '')
or with truncation and date arithmetic:
WHERE DATE_TIME >= TRUNC(CURRENT_DATE) + (5/24) AND
DATE_TIME < TRUNC(CURRENT_DATE) + (13/24)
You really need to be getting those times in the target time zone though, e.g.:
WHERE DATE_TIME >= FROM_TZ(CAST(TRUNC(CURRENT_DATE) + (5/24) AS TIMESTAMP), ''America/Los_Angeles'') AND
DATE_TIME < FROM_TZ(CAST(TRUNC(CURRENT_DATE) + (13/24) AS TIMESTAMP), ''America/Los_Angeles'')
You need to be careful with current_date, which is in you current session time zone, and sysdate which is in the server time zone. If your session is UTC then current_date might not give you the day you expect.
(I've stuck with escaped single quotes as that is mostly what you have in the question, implying you're probably running this with dynamic SQL; whether you need to is another matter. If you're only doing that to provide the period offsets at runtime then that wouldn't need to be dynamic...)
You can see the generated times from those calculations with:
select FROM_TZ(CAST(TRUNC(CURRENT_DATE) + (5/24) AS TIMESTAMP), 'America/Los_Angeles'),
FROM_TZ(CAST(TRUNC(CURRENT_DATE) + (13/24) AS TIMESTAMP), 'America/Los_Angeles')
from dual;
FROM_TZ(CAST(TRUNC(CURRENT_DATE)+(5/24)ASTIMESTAM FROM_TZ(CAST(TRUNC(CURRENT_DATE)+(13/24)ASTIMESTA
------------------------------------------------- -------------------------------------------------
2018-10-22 05:00:00.000000000 AMERICA/LOS_ANGELES 2018-10-22 13:00:00.000000000 AMERICA/LOS_ANGELES
I am trying to get the time format difference of two different times in firebird sql. I tried subtracting the two times but the result is not in time format.
TIME_IN TIME,
TIME_OUT TIME,
DIFFERENCE TIME
SELECT
TIME_IN,
TIME_OUT,
TIME_OUT - TIME_IN
Sample Data
TIME_IN = 7:00
TIME_OUT = 12:00
12:00 - 7:00
my expected output is 5:00
also tried using DATEDIFF but my result is not in time format
DATEDIFF (HOUR, TIME_IN, TIME_OUT)
Something like this:
SELECT
CAST(DATEDIFF(HOUR, CAST(EXTRACT(HOUR FROM CAST(CAST(:TIME_IN as varchar(5)) as time)) || ':00' as TIME), CAST(EXTRACT(HOUR FROM CAST(CAST(:TIME_OUT as varchar(5)) as time)) || ':00' as TIME))
|| ':' ||
DATEDIFF(MINUTE, CAST('00:' || EXTRACT(MINUTE FROM CAST(CAST(:TIME_IN as varchar(5))as time)) as TIME), CAST('00:' || EXTRACT(MINUTE FROM CAST(CAST(:TIME_OUT as varchar(5)) as time)) as TIME)) as TIME)
FROM sth
The result of DATEDIFF is an integral value for the specified type. So the result of DATEDIFF(HOUR, '07:00', '12:00') is 5, and not 5:00.
The SQL TIME datatype is only for a 24 hour time within a day, it is not for measuring duration.
If for some reason you want to format it as a time, you will need to do that yourself. For example, by taking the difference in minutes, and then calculating the correct representation in hours and minutes.
I'm open to any suggestions, so long as I get something resembling the output at the bottom of the post, TIA!
Can I get some help with this sql fiddle: http://sqlfiddle.com/#!4/c51c5/1
SCHEMA
create table history(
clockingGroup varchar2(5)
, startTime timestamp
, endTime timestamp);
insert into history
(clockingGroup, startTime, endTime)
values
('grp1', '01-dec-2015 1:00:00.000000', '01-dec-2015 1:10:10.000000');
insert into history
(clockingGroup, startTime, endTime)
values
('grp2', '01-dec-2015 1:10:10.000000', '01-dec-2015 1:20:20.000000');
insert into history
(clockingGroup, startTime, endTime)
values
('grp1', '01-dec-2015 1:20:20.000000', '01-dec-2015 1:30:35.000000');
insert into history
(clockingGroup, startTime, endTime)
values
('grp3', '01-dec-2015 1:30:35.000000', '01-dec-2015 1:35:00.000000');
SQL
select
extract(hour from (sum(cast(endTime as date) - cast(startTime as date)))) || ' Hours '
|| extract(minute from (sum(cast(endTime as date) - cast(startTime as date)))) || ' Minutes '
|| extract(second from (sum(cast(endTime as date) - cast(startTime as date)))) || ' Seconds'
as totalTime
, clockingGroup
from
history
group by
clockingGroup
Current Error
ORA-30076: invalid extract field for extract source
My desired output is:
clockingGroup | totalTime
grp1 | 0 Hours 20 Minutes 25 Seconds
grp2 | 0 Hours 10 Minutes 10 Seconds
grp3 | 0 Hours 4 Minutes 25 Seconds
You are using the built ins in the wrong order. Your original query casts your timestamps to dates. When you subtract dates from each other you get a number.
In the query below it subtracts a timestamp from a timestamp which yields an INTERVAL. You cannot extract the hour from a number but you can from an INTERVAL.
SELECT clockingGroup.
SUM(extract(DAY FROM endtime-starttime)) ||' '||
SUM(extract(HOUR FROM endtime-starttime)) ||' '||
SUM(extract(MINUTE FROM endtime-starttime)) ||' '||
SUM(extract(SECOND FROM endtime-starttime)) AS TOTALTIME,
from
history
group by
clockingGroup
I see you have added another method using numtodsinterval. You are still converting timestamps to dates which you don't need to do if you want precision.
This query is more complicated as I try and show how you take the difference and count all the intervals as seconds, sum them and then break it apart into hours/minutes/seconds
SELECT CLOCKINGGROUP, TO_CHAR(TRUNC(SUMTOTALSECONDS/3600),'FM9900') || ' Hours ' ||
TO_CHAR(TRUNC(MOD(SUMTOTALSECONDS,3600)/60),'FM00') || ' Minutes ' ||
TO_CHAR(MOD(SUMTOTALSECONDS,60),'FM00') || ' Seconds'
FROM(
SELECT clockinggroup, TRUNC(SUM(TOTALSECONDS),0) AS SUMTOTALSECONDS
FROM (
SELECT clockinggroup,
EXTRACT (DAY FROM (EndTime-StartTime))*24*60*60 +
EXTRACT (HOUR FROM (EndTime-StartTime))*60*60 +
EXTRACT (MINUTE FROM (EndTime-StartTime))*60 +
EXTRACT (SECOND FROM (EndTime-StartTime))/60 AS TOTALSECONDS
FROM history)
group by
clockingGroup)
ORDER BY 1;
I have a table called Timezone and the data looks like:
Call_ID Start_Time
93856 2011-08-04 09:59:47.000
58796 2011-08-05 14:54:37.000
25489 2011-08-09 15:32:13.000
I want the output as :
Call_ID Start_Time Interval
93856 2011-08-04 09:59:47.000 0930
58796 2011-08-05 14:54:37.000 1430
25489 2011-08-09 15:32:13.000 1530
I did something like this:
Select Call_ID , Start_Time,
CASE WHEN DATEPART(minute,Start_Time)>30 THEN
RIGHT('0' + CAST(DATEPART(HOUR,Start_Time) AS VARCHAR),2) + '30'
ELSE
RIGHT('0' + CAST(DATEPART(HOUR,Start_Time) AS VARCHAR),2) + '00'
END
From Timezone
Group By Call_ID , Start_Time,
CASE WHEN DATEPART(minute,Start_Time)>30 THEN
RIGHT('0' + CAST(DATEPART(HOUR,Start_Time) AS VARCHAR),2) + '30'
ELSE
RIGHT('0' + CAST(DATEPART(HOUR,Start_Time) AS VARCHAR),2) + '00'
END
Is there a better way of doing it?
select Call_ID,
Start_Time,
right(100+datepart(hour, Start_Time), 2)+
right(100+30*(datepart(minute, Start_Time)/30), 2) as Interval
from TimeZone
Not really any shorter, but certainly tidier with far less casts and string concatenation:
;WITH intervals(h) AS
(
SELECT TOP (48) CONVERT(TIME(0), DATEADD(MINUTE, 30*(number), '00:00'))
FROM master..spt_values
WHERE number >= 0
GROUP BY number
ORDER BY number
)
SELECT
t.Call_ID,
t.Start_Time,
Interval = REPLACE(CONVERT(VARCHAR(5), i.h), ':', '')
FROM intervals AS i
INNER JOIN dbo.TimeZone AS t
ON DATEDIFF(MINUTE, i.h, CONVERT(TIME(0), t.Start_Time)) BETWEEN 1 AND 30;
Not sure what you wanted to do if you have a value right on the boundary. Do you want it to fall in the current interval or the previous? You can change BETWEEN 1 AND 30 to BETWEEN 0 AND 29 if you want different behavior.
i have 2 rows in a column, one feeding me the julian date (number of days since Jan 1, 1970, with that day being 1), and the second column is the number of minutes past midnight of the current day (why it was done this way, i have no idea).
i would like to get my sql query to create a timestamp out of these two columns.
if i had access to the data ahead of time, i could do something like SELECT timestamp '1970-01-01 00:00:00' + INTERVAL 'X DAYS' + INTERVAL 'Y MINUTES' AS my_time FROM mytable, but since X and Y are actual members of the table i'm querying, it's not that simple.
anyone have any suggestions?
essentially, i'm looking for the equivalent [legal] solution:
SELECT timestamp '1970-01-01 00:00:00' + INTERVAL 'my_col1 DAYS' + INTERVAL 'my_col2 MINUTES' AS my_time FROm mytable
i can get my server-side code to do it for me, but i would love it if i could build it into my query.
You can construct the interval strings and then cast them to the interval type:
SELECT
timestamp '1970-01-01 00:00:00' +
cast(my_col1 || ' DAYS' AS interval) +
cast(my_col2 || ' MINUTES' AS interval) my_time FROM mytable
Without resorting to string substitution or concatenation:
SELECT
timestamp '1970-01-01 00:00:00' +
my_col1 * interval '1 DAY' +
my_col2 * interval '1 MINUTE' FROM mytable