SQL(?): Counting the time between two datetime values - sql

What is the best way to count the time between two datetime values fetched from MySQL when I need to count only the time between hours 08:00:00-16:00:00.
For example if I have values 2008-10-13 18:00:00 and 2008-10-14 10:00:00 the time difference should be 02:00:00.
Can I do it with SQL or what is the best way to do it? I'm building a website and using PHP.
Thank you for your answers.
EDIT: The exact thing is that I'm trying to count the time a "ticket" has been in a specific state during working hours. The time could be like a couple weeks.
EDIT2: I have no problems counting the actual time difference, but substracting that off-time, 00:00:00-08:00:00 and 16:00:00-00:00:00 per day.
-Samuli

The TIMEDIFF function
TIMEDIFF() returns expr1 – expr2
expressed as a time value. expr1 and
expr2 are time or date-and-time
expressions, but both must be of the
same type.
mysql> SELECT TIMEDIFF('2000:01:01 00:00:00',
-> '2000:01:01 00:00:00.000001');
-> '-00:00:00.000001'
mysql> SELECT TIMEDIFF('2008-12-31 23:59:59.000001',
-> '2008-12-30 01:01:01.000002');
-> '46:58:57.999999'

I think you should calculate the difference in your own code instead of using a more-complex SQL sentence because:
That calculation seems to be part of your business logic. It seems easier to maintain if you integrate it with the rest of your business code.
The database is often the bottleneck, so don't load it more than needed.

You may want to try it in PHP, but I'm thinking it'll be faster in DB
code to return difference in an array

Related

Hibernate query cache based on current time

I have a DAO method which executes the following query to fetch results:
SELECT new com.Person() FROM Person AS person
WHERE (person.start <= now()) AND (person.expires > now()) ORDER BY person.start ASC
The above is a PostgreSQL query. What can I do to enable query caching on the above? If I simply do query.setQueryCache(true), that wouldn't work because the now() will be different each time the above is executed. Is there a best practice to implement such functionality?
Basically you should use discrete values instead of using directly the value of now(), which is always a new one and incompatible with any caching strategy I've heard of :).
So say that you're actually looking to cache data each 15 minutes.
You'd basically have to floor the value of now() to the closest quarter of an hour and use the floored value in the SQL query instead.
You can check out this article on stack for implementing such a thing How to round time to the nearest quarter hour in java?

Can this sql-statement be shortened?

I have this SQL query to a PostgreSQL database. Can it be shortened? I am thinking about the where part.
SELECT *
FROM reservations
WHERE (starts_at BETWEEN ? AND ?) OR (ends_at BETWEEN ? AND ?)
The values for the question-marks is:
The beginning of the current date in datetime format
The end of the the current date in datetime format
Same as point one
Same as point two
The code is meant to return all the reservations that begins or ends on a certain date. And works as it is supposed to. But I have to supply the same information multiple times into the query.
I so not actually use this exactly SQL, so there might be an obvious error somewhere, but please focus on the where part
I'm not a huge fan of BETWEEN in this context, because timestampor datetime can be fractional. In particular, specifying the last possible value on a given date is much more complicated than specifying the first possible value (midnight) because you have to specify the time as 23:59:59.999... out to whatever precision your RDBMS uses. PostgreSQL's timestamp is supposed to be accurate to the microsecond (1e-6 seconds), for example, so it's easy to specify a range that either includes times you don't want, or misses times that you do.
On the other hand, if you use BETWEEN with midnight of the following day so you don't have to know the precision of the time, you're including a time that doesn't exist in the date you're interested in. If your application is only precise to the second, or the minute, or to 5 minutes, then you may mis-categorize data or, worse, count it twice since it suddenly counts as being in two dates.
I would prefer:
WHERE (starts_at >= ? AND starts_at < ?)
OR (ends_at >= ? AND ends_at < ?)
Where the ? map to:
Midnight of the target date.
Midnight of the date after the target date.
Midnight of the target date.
Midnight of the date after the target date.
It's not as short, but it's decidedly safer unless you really want to specify your intervals that precisely.
However, you should not do the following, even though it's shorter:
WHERE DATE(starts_at) = ?
OR DATE(ends_at) = ?
You don't want to do that because it's not SARGEable.
This is also an example of why shortness or brevity is a poor measure of code quality. Generally, I'd order my preference like so:
Accuracy.
Performance.
Readability/maintainability.
Brevity.
No, you can't improve upon this.
WHERE (starts_at BETWEEN ? AND ?) OR (ends_at BETWEEN ? AND ?)

SQL query date according to time zone

We are using a Vertica database with table columns of type timestamptz, all data is inserted according to the UTC timezone.
We are using spring-jdbc's NamedParameterJdbcTemplate
All queries are based on full calendar days, e.g. start date 2013/08/01 and end date 2013/08/31, which brings everything between '2013/08/01 00:00:00.0000' and '2013/08/31 23:59:59.9999'
We are trying to modify our queries to consider timezones, i.e. I can for my local timezone I can ask for '2013/08/01 00:00:00.0000 Asia/Jerusalem' till '2013/08/31 23:59:59.9999 Asia/Jerusalem', which is obviously different then '2013/08/01 00:00:00.0000 UTC' till '2013/08/31 23:59:59.9999 UTC'.
So far, I cannot find a way to do so, I tried setting the timezone in the session:
set timezone to 'Asia/Jerusalem';
This doesn't even work in my database client.
Calculating the difference in our Java code will not work for us as we also have queries returning date groupings (this will get completely messed up).
Any ideas or recommendations?
I am not familiar with Veritca, but some general advice:
It is usually best to use half-open intervals for date range queries. The start date should be inclusive, while the end date should be exclusive. In other words:
start <= date < end
or
start <= date && end > date
Your end date wouldn't be '2013/08/31 23:59:59.9999', it would instead be the start of the next day, or '2013/09/01 00:00:00.0000'. This avoids problems relating to precision of decimals.
That example is for finding a single date. Since you are querying a range of dates, then you have two inputs. So it would be:
startFieldInDatabase >= yourStartParameter
AND
endFieldInDatabase < yourEndParameter
Again, you would first increment the end parameter value to the start of the next day.
It sounds like perhaps Vertica is TZ aware, given that you talked about timestamptz types in your answer. Assuming they are similar to Oracle's TIMESTAMPTZ type, then it sounds like your solution will work just fine.
But usually, if you are storing times in UTC in your database, then you would simply convert the query input time(s) in advance. So rather than querying between '2013/08/01 00:00:00.0000' and '2013/09/01 00:00:00.0000', you would convert that ahead of time and query between '2013/07/31 21:00:00.0000' and '2013/08/31 21:00:00.0000'. There are numerous posts already on how to do that conversion in Java either natively or with Joda Time, so I won't repeat that here.
As a side note, you should make sure that whatever TZDB implementation you are using (Vertica's, Java's, or JodaTime's) has the latest 2013d update, since that includes the change for Israel's daylight saving time rule that goes into effect this year.
Okay, so apparently:
set time zone to 'Asia/Jerusalem';
worked and I just didn't realize it, but for the sake of helping others I'm going to add something else that works:
select fiels at time zone 'Asia/Jerusalem' from my_table;
will work for timestamptz fields

When to use separate date and time instead of a single datetime

If I want to store date and time, is it better to store them in a separate date and time or use a single datetime?
When should we use date and time instead of a single datetime?
I want to filter my queries either using date or time.
When you are talking about a moment in time, whether a universal moment, or a specific date and time on someone's local calendar, you use a datetime. If you want to be sure that you are talking about an exact moment in time, regardless of the observer, then you use a datetimeoffset.
If you are storing just a date then you mean a date without a time component, meaning "any time on this date".
If you are storing just a time then you mean a time without a date component, meaning "this time on any date", or "this time on a date determined by some other means".
There is no practical purpouse to having both a date and a time that are about the same thing, sitting on the same row. Just use a datetime for that.
In SQL Server 2008 you have date and time data types so this becomes a non issue.
If it is good choice it really depends by your business and how you will query you data.
If for example you want to know all the orders places between 1 and 2 PM for any day using a separated Date and Time column will make it quicker
If you intentionally do not care about the time, it's more efficient to store this data as a date datatype. Think a customer birthday column, there's not too many cases I can think of that would use this time. If there happens to be a time attached to it (often a bug), this needs to be removed via a convert statement in order to do a compare. It also consumes additional space if you don't need these values (3 bytes compared to 8).
I think it's similar to having a status code table with the id as a bigint instead of a tinyint or the like (depending on how many status codes you would plan to have).
It's just a matter of what you're using the data for, if you think there's a good chance you'll ever need the that data, then use datetime, otherwise use date.
Nothing brilliant about separating date and time,
Better you save date and time in Same column,
Here they have discussed the same issue check it : are-there-any-good-reasons-for-keeping-date-and-time-in-separate-columns
you can also get date and time separately by query
SELECT
CONVERT(VARCHAR(10),GETDATE(),111) as DatePart,
convert(varchar(15), getdate(), 108) TimePart

What use are SQL dates without date functions?

I've worked with various ORMs and database abstractions designed to make it easy to work with multiple databases, both relational and not. The more comprehensive solutions will usually give you access to some date functions that boil down to actual SQL (or whatever, in the case of non-SQL dbs). On the other hand, many of these abstractions don't provide direct access to SQL functions and you lose the ability to deal with dates directly. Instead, you're expected to use the upper-level language (PHP, Python, whatever) to do your date-wrangling, and finally only insert, select, what-have-you the formatted date.
So my question is this: if the SQL server never gets to do anything with the date itself, am I better off just using an int and putting epoch timestamps in it, or is there additional value to the database server "knowing" it's a date?
If you are using dates, store them as dates.
Not only does this make it easier to translate between the database and application, but when you need to do anything based on the dates (and you will, otherwise why have dates stored at all?).
That is, when you need to sort or query using the dates, you will not need to go trough special effort to re-convert to dates.
Other than what #Oded said, if you never ever use any date related functions, Still there are some issues;
At the moment, you cannot store epoch timestamp in milliseconds into an INT field (overflows).
Timestamp without milliseconds will overflow INT on Tue Jan 19 2038 # 03:14:08 GMT+0000 (GMT) as it will be greater than 2147483647.
BUT, Integer takes 4 bytes and Datetime takes 8 bytes. You are better off 4 bytes if you are within above two limitations.