I have a model "Competition" with attributes start_at and end_at, both of type datetime. I would like to retrieve only competitions with a duration shorter that a given amount, for example 3 days. I would expect to do this easily:
Competition.where('end_at - start_at < ?', X)
The problem: what do I use for X?
In my database I have one competition object with a duration of slightly less than one day (start_at = 2011-04-27 00:00:00, end_at = 2011-04-27 23:59:59) and one slightly less than 3 days (start_at = 2013-02-05 00:00:00, end_at 2013-02-07 23:59:59), all others are much longer.
To retrieve the shorter of the two, I expected to use X = 60*60*24 (number of seconds in 24 hours). Doesn't work. SO I tried to multiply by an increasing factor and found that multiplying X by 2.7 will not retrieve it, but 2.8 will ! So OK, I need to use this strange factor 2.8...
But this does not work for retrieving objects shorter than 3 days. Here I need to multiply by 8.7. Does anybody know what's going on here?
The functions available depend on the database you're using. For example, with SQLite, you can use:
Competition.where('julianday(end_at) - julianday(start_at) < ?', 3)
Try this:
Competition.where('DATEDIFF(end_at, start_at) < ?', x)
For more accurate
Competition.where('TIMESTAMPDIFF(SECOND, start_at, end_at) < ?', x*86400) #where 86400 is the seconds in a day and x is no. of days
Related
I am trying to find a way to filter records where the difference in two date/time fields is less than 90 minutes.
Example:
orders.created_at = 2015-08-09 20:30:20
table2.created_at = 2015-08-09 20:09:30
I have tried using TimeDiff, although I don't understand how the syntax would apply to this example.
Data comes from separate tables both linking to the same order information. The aim is to find examples of where an order has been placed within 90 minutes, but a third field has not been updated. I would be using an AND query for only including results where a third field is NULL
In mysql, you need to use TIMEDIFF() or UNIX_TIMESTAMP for this. I prefer the UNIX_TIMESTAMP solution because it's simpler:
WHERE
thirdfield IS NULL
AND UNIX_TIMESTAMP(orders.created_at) - UNIX_TIMESTAMP(table2.created_at) < 5400
WHERE
thirdfield IS NULL
AND UNIX_TIMESTAMP(orders.created_at) - UNIX_TIMESTAMP(table2.created_at) < 5400
Does that work both ways, or do you have to expand to "(A-B < 5400 AND A-B >0) OR (B-A <5400 AND B-A > 0)"?
((UNIX_TIMESTAMP(orders.created_at) - UNIX_TIMESTAMP(table2.created_at) < 5400)
AND (UNIX_TIMESTAMP(orders.created_at) - UNIX_TIMESTAMP(table2.created_at) > 0))
OR ((UNIX_TIMESTAMP(table2.created_at) - UNIX_TIMESTAMP(orders.created_at) < 5400)
AND (UNIX_TIMESTAMP(table2.created_at) - UNIX_TIMESTAMP(orders.created_at) > 0))
The price calculations for the product I rent out is very complicated, and basically signature for it looks like this:
price = f( from_date, to_date, x ) - i.e dependent on 3 parameters: from_date, to_date, x, where from_date and to_date are dates, and x is a numeric (int) value in range from 1 to 10.
f - is the complicated underlying function.
Main constraints:
1) from_date accept values [ today; today + 1 year ]
2) to_date > from_date
3) |(to_date - from_date)| takes values from [1..365]
I use MySQL as my main storage and I have around 50,000 items.
And I would like to build a search page, where you could filter or sort by price (after entering dates; x defaults to 1 if omitted).
I understand that this cannot be converted into MySQL query, because it is too complicated (and even if was possible, it would be very slow and inefficient).
I thought that maybe I could use a key-value storage like redis or memcache to pre-calculate price values for all possible date ranges, store them there, and invalidate if needed (and that will not happen often).
But, using some basic math, I figured out that using this approach I would need at most 33,580,500,000 keys: (366 * 367 / 2) * 10 * 50,000
And my question is - I'm I thinking in right direction?
If yes - are there any efficient solutions (in terms of # of keys, memory footprint and scalability) to this problem?
Thanks in advance!
In my users table I have a field hours, and when I'm selecting all my users I need to also get a variable fullTime which will be based on if hours equals 7.4. Is this something I can do in a query rather than having to loop through all the users? I have 600+ rows and I'm trying to do this the most efficient way as this happens on every page load. I was thinking something like SELECT *, fullTime as (hours EQUALS 7.4) FROM users
EDIT: Working SQL SELECT * , IF(hours_per_day = 7.5, 1, 0) AS fullTime FROM users
The following will return a column with fulltime = 1 if hours = 7.4 and fulltime = 0 otherwise.
SELECT *, IF(hours = 7.4, 1, 0) AS fulltime FROM users
Note that this may fail if hours is a float column due to inaccuracies in floating point numbers.
try this
SELECT * , if(hours >= 7.4 ,col_time, hours) as fullTime FROM users
explanation :
if hours >=7.4 (not only exactly hours=7.4 but also greater.) you will get your column where you stored the full date with time or whole time. you can even change it by DATE_FORMAT. otherwise you will get the hours lets say 5 ,or something.
I have complicated query over very big table.
Long story short, when I use convert time to select period of day (let's say 12-13h, converting it from datetime row) query takes few minutes, instead of few seconds without convert!
So, I tried datepart, and it works well, almost instant, but, problem is, how to point to hours and minutes in same time?
Any other fast solution is more than welcome.
Thanks.
Meanwhile I came up with this:
DATEPART(HOUR, datetimecolumn)*100 + DATEPART(MINUTE, datetimecolumn)) between 1210 and 1540
You can use datePart if you are willing to do a bit of math, as shown below:
12:10 = 12 * 60 + 10 = 730 minutes
15:40 = 15 * 60 + 40 = 940 minutes
select * .....
where datepart(mi, datefield) between (12*60+10) and (15*60+40)
If you have a constant periods - i.e. - always hourly and no any floating periods - you may introduce something like "ordinal number of period" calculated field, index on it and query of it with precalculated period value
OR
is there are no any constant periods - try to calculate proper begin and end values prior to SELECT statement and use them in the query.
Keep in mind that using functions in where clause of query - sometimes is a bad idea. Using functions in ORDER BY clause - always bad
You can get GETTIME from following Function
alter function GetTimeOnly(#_DateTime DateTime)
returns datetime
as
begin
return dateadd(day, -datediff(day, 0, #_datetime), #_datetime)
end
go
OR YOU CAN HAVE THE TIME FROM CONVERT FUNCTION.
SELECT
CONVERT(VARCHAR(8),GETDATE(),108) AS HourMinuteSecond,
CONVERT(VARCHAR(8),GETDATE(),101) AS DateOnly
Ok, I need something like this:
datediff(second, date_one, date_two) < 1
dates are stored in a column 'datetime' type
UPDATE
I want to find dates which differ in less than several (say, 10) seconds
Second is the smallest unit in DATETIME fields. If you want to check that the difference is less than 1 second, that means that the two dates must be the same, in which case you can simply use the equivalency operator.
To check the time difference using bigger units you can use TIMEDIFF with TIME_TO_SEC. For example to check if two datetimes are between 10 seconds of each other
ABS(TIME_TO_SEC(TIMEDIFF(datetime1, datetime2))) < 10
ABS(TIMESTAMPDIFF(SECOND, datetime1, datetime2)) < 10
This allows for easily changing the units and it is now possible to do such comparisons using MICROSECOND as well.