Storing the time in Oracle - sql

Let me quickly explain. I have an application to manage visitors.
We have a start date of the visit (a visit can only be for one day).
We can add a time for example the time of a tour, the time the group will be having lunch, the time the group will be having a presentation etc. All times will take the start date of the visit and then append the time accordingly.
Simple code:
// set tour time in tour table
$y->setTourTime($visit->getVisitDate("Y-m-d") . $tourTime);
// can have many presentation
$p->setPresentationTime($visit->getVisitDate("Y-m-d") . $tourTime);
So I have many time stamps across multiple tables. The problem I have however, if I decide to change the start date in the visit entity, then I'll have to change all of the timestamps across the related tables (tour guide, lectures etc.) This is ugly
What I would prefer is to have a visit date, such as 2010-10-10 in the visit table. And then in the lecture tables, guide tables etc. to just store the time and not the date. How would you do that? just store it as a string, i.e. "10:00"?
Thanks for any input. :-)

You have several possibilities. I prefer to have datatypes that are best suited for the job. Calculating with times is best done using DATE, TIMESTAMP and INTERVAL, so I'd use something like this:
SQL> create table visits
2 ( startdate date
3 , starttime_tour interval day(0) to second(0)
4 , starttime_lunch interval day(0) to second(0)
5 , starttime_presentation interval day(0) to second(0)
6 , constraint visits_ck1 check (startdate = trunc(startdate))
7 )
8 /
Table created.
You can read more about the INTERVAL DAY TO SECOND datatype here: http://download.oracle.com/docs/cd/E11882_01/server.112/e17118/sql_elements001.htm#SQLRF00207
And here is an example how you insert and select from it:
SQL> insert into visits
2 values
3 ( trunc(sysdate)
4 , to_dsinterval('0 09:00:00')
5 , to_dsinterval('0 12:00:00')
6 , to_dsinterval('0 13:00:00')
7 )
8 /
1 row created.
SQL> select startdate
2 , starttime_tour
3 , starttime_lunch
4 , starttime_presentation
5 from visits
6 /
STARTDATE STARTTIME_TOUR STARTTIME_LUNCH STARTTIME_PRESENTATI
------------------- -------------------- -------------------- --------------------
17-12-2010 00:00:00 +0 09:00:00 +0 12:00:00 +0 13:00:00
1 row selected.
And calculating is very easy now:
SQL> select startdate
2 , startdate + starttime_tour as tour
3 , startdate + starttime_lunch as lunch
4 , startdate + starttime_presentation as presentation
5 from visits
6 /
STARTDATE TOUR LUNCH PRESENTATION
------------------- ------------------- ------------------- -------------------
17-12-2010 00:00:00 17-12-2010 09:00:00 17-12-2010 12:00:00 17-12-2010 13:00:00
1 row selected.
Hope this helps.
Regards,
Rob.

If you want to manipulate as a time it might be better to just create two date fields. One holds the visit date, the other holds the tour time with a generic date attached (1/1/2000 or something consistent & non-specific) - you ignore the date portion of the tour time but can still do time-based comparisons if necessary without converting a string to a time value.

Related

Compare date and time in SQL for DB2

I need to compare date and time of 2 fields and see if its greater than 24 hours however there is another field whose value is less than the 24 hours of the compared date. For example ,
create date - 18/7/2019 11:15 AM
target date - 19/07/2019 11:16 AM
There is a gap of 24 hours here
Actual date - 19/07/2019 10:45 AM
Actual date is less than above said gap of 24 hours . Hence the query should return such records that has actual date less than the create date and target date gap of 24 hours. Here all the fields are of DATETIME data type in DB2 database.
It's not clear what you really try to do.
Actual date is less than above said gap of 24 hours
How can a date may be comparable to a gap (or time duration)?
Should we understand it as:
Gap between actual and created is less than gap between target and created?
If so, then try the following:
select *
from
(
select create, target, actual
, timestampdiff(8, char(target - create)) gap_target
, timestampdiff(8, char(actual - create)) gap_actual
from table(values
(timestamp('2019-07-18-11.15.00'), timestamp('2019-07-19-11.16.00'), timestamp('2019-07-19-10.45.00'))
) t (create, target, actual)
)
where
gap_target >= 24 and gap_actual < 24
-- or some another expression like:
-- gap_actual < gap_target
;
CREATE TARGET ACTUAL GAP_TARGET GAP_ACTUAL
------------------- ------------------- ------------------- ---------- ----------
2019-07-18 11:15:00 2019-07-19 11:16:00 2019-07-19 10:45:00 24 23
Is this what you want?
If not, then provide a few number of input records and the exact result desired.

Find the minute difference between 2 date time

I need to get the difference between 2 date time in minutes(Time difference in minutes). And the last difference will be calculated based on 6 PM of every date.
Sample data: need result of last column
User_Name Date Time difference in minutes
User 1 1/1/06 12:00 PM 30
user 2 1/1/06 12:30 PM 315
user 3 1/1/06 5:45 PM 15
Here the date will be always in same date and the last user date difference calculated based on default value 6PM. Assuming the dates of any user will not cross 6PM time.
Please suggest how to write the query for the same.
You could use the lead window function.
I assume your table is called mytable and the date column is mydate (it is a bad idea to call a column Date as it is a reserved word).
select user_name,
round((lead(mydate, 1, trunc(mydate)+18/24)
over (partition by trunc(mydate) order by mydate)
- mydate) *24*60) as difference
from mytable
I found the solution.. if its not correct let me know
SELECT User_name,created_date,
trunc(to_number((cast(nvl(lead (created_date,1) OVER (ORDER BY created_date),TRUNC(SYSDATE) + (19/24)) as date) - cast(created_date as date)))*24*60) as difference
FROM users;

Check if a time period is included in another time period

In my db i have many record, with start date and length of that time of period.
For example
id start_date lenght
1 2013-01-01 00:00:00 20
2 2013-02-30 00:00:00 10
3 2013-01-20 00:00:00 3
So i can easily get the end date.
Now if the user gave me any period of time, how can I control if that period is included in one of the time period that I have in the db?
Thank you.
You can get the list using a where clause and the date functions:
select *
from t
where XXX between start_date and date_add(start_date, interval length day);
EDIT:
The above is for one date. If the user gives two date, XXX and YYY, then this is what you want for any overlap:
select *
from t
where XXX <= date_add(start_date, interval length day) and
YYY >= start_date;
That is, the period the user gives you starts before the end of the interval and the period ends after the start of the interval.

SQL Select Count Column Between two Times

I have the database where I have two columns - date (incl. time) and minutes - as follows:
Open_Time Minute
2013-01-01 09:00:00.000 1
2013-01-01 09:01:00.000 1
2013-01-01 09:02:00.000 1
2013-01-01 09:03:00.000 1
2013-01-01 09:04:00.000 1
2013-01-01 09:05:00.000 1
How to count the minutes between the first and last date time?
select COUNT(Minute)
from test_table
where open_time between '2013-01-01 09:00:00.000' and '2013-01-01 09:05.000'
does not work for me.
I will need to count the minutes as current time - open time in the future.
Thank you for any feedback!
for mysql may be can use :
SELECT TIMESTAMPDIFF(MINUTE,'2013-01-01 09:00:00.000','2013-01-01 09:05.000') ; // return result as minutes
read here : http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html
The SQL looks fine although it returns 6. Did you want that or did you want 5? You could always just start your SELECT criteria from 09:01:00.000 if that's what you want.
SQLfiddle here: http://sqlfiddle.com/#!2/d3f13/2
I am not getting exactly what you want. But if want to extract minute from your date then use following query.
SELECT EXTRACT(MINUTE FROM Open_Time) FROM test_table;
SELECT EXTRACT(MINUTE FROM Open_Time)-10 FROM test_table;
Above query will give only difference in minute. so check you DAY,HOUR,MINUTE,SECONDS based on your criteria
In sql server you can use DATEDIFF function,wich accept folowing parameters:
DATEDIFF(datepart,startdate,end date) and returns count(int) between specified date boundaries for selected datepart,so you could use something like this:
select DATEDIFF(mi,MIN(opentime),MAX(opentime)) AS 'minutes'
from test_table
where open_time between '2013-01-01 09:00:00.000' and '2013-01-01 09:05.000'
You also cloud count minutes from column "minutes",but it will be very hard to count them with current date(unless,every time when counting you insert current time in the table,or create temp table) !

How to find first free time in reservations table in PostgreSql

Reservation table contains reservations start dates, start hours and durations.
Start hour is by half hour increments in working hours 8:00 .. 18:00 in work days.
Duration is also by half hour increments in day.
CREATE TABLE reservation (
startdate date not null, -- start date
starthour numeric(4,1) not null , -- start hour 8 8.5 9 9.5 .. 16.5 17 17.5
duration Numeric(3,1) not null, -- duration by hours 0.5 1 1.5 .. 9 9.5 10
primary key (startdate, starthour)
);
table structure can changed if required.
How to find first free half hour in table which is not reserved ?
E.q if table contains
startdate starthour duration
14 9 1 -- ends at 9:59
14 10 1.5 -- ends at 11:29, e.q there is 30 minute gap before next
14 12 2
14 16 2.5
result should be:
starthour duration
11.5 0.5
Probably PostgreSql 9.2 window function should used to find
first row whose starthour is greater than previous row starthour + duration
How to write select statement which returns this information ?
Postgres 9.2 has range type and I would recommend to use them.
create table reservation (reservation tsrange);
insert into reservation values
('[2012-11-14 09:00:00,2012-11-14 10:00:00)'),
('[2012-11-14 10:00:00,2012-11-14 11:30:00)'),
('[2012-11-14 12:00:00,2012-11-14 14:00:00)'),
('[2012-11-14 16:00:00,2012-11-14 18:30:00)');
ALTER TABLE reservation ADD EXCLUDE USING gist (reservation WITH &&);
"EXCLUDE USING gist" creates index which disallows to inset overlapping entries. You can use the following query to find gaps (variant of vyegorov's query):
with gaps as (
select
upper(reservation) as start,
lead(lower(reservation),1,upper(reservation)) over (ORDER BY reservation) - upper(reservation) as gap
from (
select *
from reservation
union all values
('[2012-11-14 00:00:00, 2012-11-14 08:00:00)'::tsrange),
('[2012-11-14 18:00:00, 2012-11-15 00:00:00)'::tsrange)
) as x
)
select * from gaps where gap > '0'::interval;
'union all values' masks out non working times hence you can make reservation between 8am and 18pm only.
Here is the result:
start | gap
---------------------+----------
2012-11-14 08:00:00 | 01:00:00
2012-11-14 11:30:00 | 00:30:00
2012-11-14 14:00:00 | 02:00:00
Documentation links:
- http://www.postgresql.org/docs/9.2/static/rangetypes.html "Range Types"
- https://wiki.postgresql.org/images/7/73/Range-types-pgopen-2012.pdf
Maybe not the best query, but it does what you want:
WITH
times AS (
SELECT startdate sdate,
startdate + (floor(starthour)||'h '||
((starthour-floor(starthour))*60)||'min')::interval shour,
startdate + (floor(starthour)||'h '||
((starthour-floor(starthour))*60)||'min')::interval
+ (floor(duration)||'h '||
((duration-floor(duration))*60)||'min')::interval ehour
FROM reservation),
gaps AS (
SELECT sdate,shour,ehour,lead(shour,1,ehour)
OVER (PARTITION BY sdate ORDER BY shour) - ehour as gap
FROM times)
SELECT * FROM gaps WHERE gap > '0'::interval;
Some notes:
It will be better not to separate time and data of the event. If you have to, then use standard types;
If it is not possible to go with standard types, create function to convert numeric hours into the time format.