Mysql wildcard query problem - mysql

WHERE `time` BETWEEN 'Jan 1 %' AND 'Jan 8 %' AND ...
Results
Jan 1 00:33:23
Jan 10 08:52:05
How would I avoid the Jan 10 results?
I have tried a few different combination with %, <=, etc.
Any ideas?
Thanks

WHERE Time >= '1/1/2011' AND Time < '1/9/2011'
Or, if you want results from any year:
WHERE DATEPART( month, Time ) = 1 AND DATEPART( day, Time ) < 9

Currently with this query you confuse the search engine because "between" is designed for use with numbers or dates, while you use it with strings.
There are 2 solutions to your problem:
1) Convert your "time" field to "date" and store the dates as "01-01-2010 00:00" (This is the most healthy solution as you will make the DB aware that is a date field)
2) Try:
WHERE `time` >= 'Jan 1' AND `time` < 'Jan 2'
The second solution may give strange results as it is comparing 2 strings, not 2 dates.

I can't try it for you here, but why don't you try around with the STR_TO_DATE method? You can change your time field to a real date, and then don't need to do that string compare:
WHERE STR_TO_DATE(`time`,'%d,%m,%Y') BETWEEN
'2010-01-01'
AND
'2010-01-09'
also, see http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_str-to-date

Related

MYSQL Function STR_TO_DATE

I have date in this date:
STR_TO_DATE('28-AUG-60','%d-%M-%y')
And when i do insert into table i got:
2060-08-28 00:00:00
What do i expected:
1960-08-28 00:00:00
I know that in MSSQL there is a format RR and its gave you 2 or 4-digit year, 20th century for 00-49 how do i do that in MySQL ?
When is look at documentation i got that it will works with %Y but it doesn't
Thank you !
If you know that all 2-digit years above some value, say '50', should be considered as years in the 1900s and the rest should be considered as years in the 2000s, you can use a CASE expression so that you apply a different date format:
SELECT DATE(STR_TO_DATE(
date,
CASE WHEN RIGHT(date, 2) < ? THEN '%d-%M-%Y' ELSE '%d-%M-%y' END
)) date
FROM tablename;
Change ? to the 2-digit year (like '50') that suits your data.
See the demo.
Two digit years cause a problem, because you don't know what centry they are in. MySQL has this well documented in the second of documentation called 2-Digit Years in Dates.
Basically, the cutoff is 2069 rather than 2050.
If you want the years between 1950 and 1969 to be represented, then you can use:
(case when str_to_date('28-AUG-60', '%d-%M-%y') >= '2050-01-01'
then str_to_date('28-AUG-60', '%d-%M-%y') - interval 100 year
else str_to_date('28-AUG-60', '%d-%M-%y')
end)
You are using wrong year format try use '%Y' (instead of '%y')
select STR_TO_DATE('28-AUG-60','%d-%m-%Y')

MySql timestamp rounding then reformatting in human readable format

I have the following query from Group OHLC-Stockmarket Data into multiple timeframes - Mysql.
SELECT
FLOOR(MIN(`timestamp`)/"+period+")*"+period+" AS timestamp,
SUM(amount) AS volume,
SUM(price*amount)/sum(amount) AS wavg_price,
SUBSTRING_INDEX(MIN(CONCAT(`timestamp`, '_', price)), '_', -1) AS `open`,
MAX(price) AS high,
MIN(price) AS low,
SUBSTRING_INDEX(MAX(CONCAT(`timestamp`, '_', price)), '_', -1) AS `close`
FROM transactions_history -- this table has 3 columns (timestamp, amount, price)
GROUP BY FLOOR(`timestamp`/"+period+")
ORDER BY timestamp
In my select statement, FLOOR(MIN(timestamp)/"+period+")*"+period+" AS timestamp,
I am trying to understand what it is doing. and
I need to convert this back to a mysql date/time Y-M-D H:i:s string or a UTC timestamp for parsing via javascript.
Let's assume that +period+ is 86400 (The number of seconds in a day)
Let's assume that the timestamp is '2015-12-08 20:58:58'
From what I can see, it takes the timestamp, which internally is stored as an integer and divides by 86400.
'2015-12-08 20:58:58' / 86400 = 233231576.4566898000
It then uses the FLOOR operation which would make it 233231576 then multiplies by 86400 again (I assume that this is to ensure rounding to the day)
I end up with 20151208166400.
So that's the 8th December 2015 but I also have 166400 which I have no idea what it is?
So now the second part of the question is, how to convert this integer to 2015-12-08 %H:%i:%s or even a UTC timestamp for parsing via Javascript.
I mentioned the problem in the comment, but not a fix. The problem is that the proposed code is for a unix timestamp, not a datetime value.
This can be fixed by doing appropriate conversions
SELECT FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(MIN(timestamp)) / $period) * $period)
This gives you the flexibility of have arbitrary numbers of seconds for the groupings.
You're right that FLOOR(timestamp / 86400) * 86400 is a crude way of rounding a UNIX-style timestamp (seconds since 1970-01-01 00:00UTC) to midnight on the present day UTC.
If that's what you're trying to do, I suggest you try this kind of MySQL code:
SELECT DATE_FORMAT(DATE(`timestamp`), '%Y-%m-%d'),
...
GROUP BY DATE(`timestamp`)
This uses MySQL's built in date arithmetic to turn a timestamp into midnight.
But you should be careful of one thing. Those timestamps are all stored in UTC (f/k/a Greenwich Mean Time). When you do date arithmetic with them, or pull them out of the database to use them, they're automatically converted to local time according to your MySQL time zone settings.
It is rounding timestampt to period (e.g day).
DATE_FORMAT( DATE( FLOOR(MIN(timestamp)/"+period+")*"+period+" ) , '%Y-%m-%d %H:%i:%s' )
If period==day consider using only MySQL period rounding by DAY().
Convert a Date object to a string, according to universal time:
var d = new Date();
var n = d.toUTCString();
The result of n will be:
Mon, 28 Dec 2015 12:57:32 GMT

Compare two unix time stamps to see if they are on the same date in MySql

I have read various questions here on Stackoverflow about the use of FROM_UNIXTIME but none directly deal with what I am trying to do. I have one timestamp in a variable coming from php (that has been reformatted - e.g. 25 March 2014) to a function which uses a database query to determine if there are other entries in the database that have the same date (not time). I've run across various methods for formatting and comparing timestamp entries using MySql and ended up with the following but I understand that it isn't very efficient. Does anyone know of a better way to accomplish this?
FROM_UNIXTIME(sd.timestart, "%e %M %Y") = ?'
where the variable in my array for comparison is the date format listed above. This accomplishes what I want but, again, I don't think it is the most efficient way to get this done. Any advice and/or ideas will be much appreciated.
*EDIT*
My timestamp is stored as an integer so I'm trying to use:
$thissessiondate = strtotime($date->timestart, strtotime('today'));
and
$tomorrowdate = strtotime($date->timestart, strtotime('tomorrow'));
to do trim to midnight but get an error (strtotime() expects parameter 2 to be long) and when I move 'today' to the first argument position, I get a conversion to 11 pm instead of 0:00...? I'm making some progress but my very incomplete knowledge of both PHP and MySQL are holding me back.
If you can avoid it, don't wrap columns used in predicates in expressions.
Have your predicates on bare columns to make index range scans possible. You want the datatype conversion to happen over on the literal side of the predicate, wherever possible.
The STR_TO_DATE function is the most convenient for this.
Assuming the timestart column is DATE, DATETIME or TIMESTAMP (which it really should be, if it represents a point in time.)
WHERE sd.timestart >= STR_TO_DATE( ? , "%e %M %Y")
AND sd.timestart < STR_TO_DATE( ? , "%e %M %Y") + INTERVAL 1 DAY
Effectively, what that's doing is taking the string passed in as the first argument to the STR_TO_DATE function, MySQL is going to convert that string to a DATETIME, based on the format specified as the second argument. And that effectively becomes a literal that MySQL can use to compare to the stored values in the column.
If there's an appropriate index available, MySQL will consider an index range scan operation to satisfy that predicate.
You'd need to pass in the same value twice, but that's not really a problem.
On the second line, we're just adding a day to the same value. So what MySQL is seeing is this:
WHERE sd.timestart >= STR_TO_DATE( '25 March 2014' , "%e %M %Y")
AND sd.timestart < STR_TO_DATE( '25 March 2014' , "%e %M %Y") + INTERVAL 1 DAY
In terms of performance, that's equivalent to:
WHERE sd.timestart >= '2014-03-15 00:00:00'
AND sd.timestart < '2014-03-16 00:00:00'
If you do it the other way around, and wrap timestart in a function, that's going to require MySQL to evaluate the function on every single row (or at least, on every row that isn't filtered out by another predicate first.)
IMPORANT NOTE
Be aware that MySQL interprets datetime values as being in the timezone of the MySQL connection, which defaults to the timezone setting of the MySQL server. MySQL is going to interpret datetime literals in the current setting of the timezone. For example, if MySQL timezone is set to +00:00, then datetime literals will be interpreted as UTC.
I assumed the format string matches the data being passed in, I don't use %e or %m. The %Y is a four digit year. (The list of format elements is in the MySQL documentation, under the DATE_FORMAT function.
Reference: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_str-to-date
If your timestart column is INTEGER or other numeric datatype, representing a number of seconds or some other unit of time since the beginning of an era, you can use the same approach for performance benefits.
In the predicate, reference bare columns from the table, and do any conversions required on the literal side.
If you aren't using MySQL functions to do the conversion to "seconds since Jan 1, 1970 UTC" when rows are inserted (which is really what the TIMESTAMP datatype is doing internally), then I wouldn't recommend using MySQL functions to do the conversion in the query either.
If you're doing the conversion from date and time to an integer type "timestamp" in PHP, then I'd do the inverse conversion in PHP as well, and do the trimming to midnight and the adding of a day in PHP.
In that case, your MySQL query would be of the simple form:
WHERE sd.timestart >= ?
AND sd.timestart < ?
Where you would pass in the appropriate integer values, to compare to the INTEGER timestamp column.
Note that MySQL does provide a function for converting to "seconds since Jan 1 1970 UTC", so if timestart is seconds since Jan 1 1970 UTC, then something like this is valid:
WHERE sd.timestart >= UNIX_TIMESTAMP(STR_TO_DATE( '25 March 2014' , "%e %M %Y"))
AND sd.timestart < UNIX_TIMESTAMP(STR_TO_DATE( '25 March 2014' , "%e %M %Y") + INTERVAL 1 DAY)
BUT... again, be aware of timezone conversion issues; if the MySQL database has a different timezone setting than the web server. If you are going to store "integer", then I wouldn't muck that up with the conversion that MySQL does, which may not be exactly the same as the conversion functions the web server does.
If you store your date as an int timestamp, you can do this
round(sd.timestart/86400)=round(UNIX_TIMESTAMP(NOW())/86400)
This will get everything in your database that is from the same day.
For example:
SELECT id FROM uploads WHERE (approved=0 OR approved is NULL) AND round(uploads.date/86400)<=round(UNIX_TIMESTAMP(NOW())/86400) order by uploads.date DESC LIMIT 20
Will display all the uploads for today and the days before, without showing the future uploads. 86400 is the number of seconds in one day.

Select query for two weeks ago

In my database table I have a field for date (varchar field to save date in yy-mm-dd format ), now I want to select records for two weeks ago.
How can i do it ?
Implicit date arithmetic is fairly flexible in MySQL. You can compare dates as strings without explicit use of CAST() or DATE(), but you're trusting MySQL to interpret your format correctly. Luckily for you, it will do just fine with yy-mm-dd.
I would recommend using BETWEEN and INTERVAL so that your query is easily readable; for example:
SELECT * FROM Holidays
WHERE Date BETWEEN (NOW() - INTERVAL 14 DAY) AND NOW();
The only trick with BETWEEN is that you have to put the lower bound first and the upper bound second; for example, if you write BETWEEN 5 AND 2, this always evaluates to FALSE because there is no value that can be greater than or equal to 5 while also being less than or equal to 2.
Here's a demo of the query in action at SQL Fiddle, and a list of the recognized INTERVAL expressions in MySQL.
Note that the parentheses around the expression NOW() - INTERVAL 14 DAY are not required but I would recommend using them here purely for the sake of clarity. It makes the predicate clause just a little bit easier to read in the absence of proper syntax highlighting, at the expense of two characters.
Ideally you should be using date types to store dates, but being that's not the case, you should look into casting to date then comparing.
select * from yourtable where cast (yourdate as Date) BETWEEN Date_Add(CURDATE(), INTERVAL -21 Day) and Date_Add(CURDATE(), INTERVAL -14 Day)
Note, this is untested and may need a little tweaking, but should give you a general idea of what you need to do.
Also, if it's possible, you should really look into converting the varchar field to a date field....they have date types to prevent this sort of thing from happening, although i know changing field types isn't always a possibility.
you can simply do with ADDDATE to get 14 days ago. compare string with date will work.
SELECT *
FROM your_table
WHERE your_date >= ADDDATE(NOW(), -14) AND your_date < NOW()
I use this for select data in past of past
SELECT * FROM Holidays
WHERE a.dDate >= DATE( NOW( ) ) - INTERVAL 14
DAY AND a.dDate <= DATE( NOW( ) ) - INTERVAL 8

MySQL - BETWEEN will not select correct results

I am trying to select rows that are in between two dates. First, here is my data:
punch_id eid time unixtime punch_type day date doy
135 2 12:53 1314723193 0 4 08/28/2011 241
134 2 12:53 1314723190 3 4 08/31/2011 241
133 2 12:53 1314723187 2 4 08/20/2011 241
132 2 12:52 1314723125 1 4 08/30/2011 241
I have tried these two queries.
SELECT * FROM `punches` WHERE `date` >= '08/20/11' AND `date` <= '08/31/11'
SELECT * FROM `punches` WHERE `date` BETWEEN '08/20/11' AND '08/31/11'
Neither of these select the rows containing the date 08/31/11. It selects the 08/20/11 ones though. I tried to use it another way and when I run the query:
SELECT * FROM `punches` WHERE `date` >= '08/10/11' AND `date` <= '08/20/11'
I again do not get the correct result: the 20th is left out once again. What is the problem with the way I am executing this?
See this related question.
As others have mentioned, your primary problem is not accounting for the time. A few options to handle that:
Use a function to convert the DateTime to a Date. I don't recommend this option, since it will likely make the function non-sargeable.
Expand your BETWEEN to explicitly include the last moment of the day: (note: this is the latest possible value that MS SQL can store, don't know if MySQL has the same value)
SELECT * FROM `punches` WHERE `date`
BETWEEN '08/20/11 00:00:00.000' AND '08/31/11 23:59:59.997'
Use a < for the upper value
SELECT * FROM `punches` WHERE `date` >= '08/20/11' AND `date` < '09/01/11'
I actually think that last one is easier, in most situations.
I suppose you could do other things, like change the datatype of the column, but I've assumed here that you're just interested in changing the query.
** Disclaimer: I'm a MS SQL guy, not MySQL
I don't know mysql, but in other RDBMS, dates are assuming a time part of 12 AM. If you want to include the high date, add 1 to the day.
Is your date field of type DATE or DATETIME?
It probably has to do with the time of day. If you have a DATETIME stored as
2011-08-31 13:00:00
then it won't match on
BETWEEN '08/20/11' AND '08/31/11'
You'd have to use
BETWEEN '08/20/11' AND '09/01/11'
The MySQL docs for between say it matches "less than or equal to" max, so it is probably the time of day throwing you off.
When you don't specify a time with the date, then 00:00:00 is implied. Therefore the real query that the database is doing is more like...
SELECT * FROM `punches` WHERE `date` BETWEEN '08/20/11 00:00:00' AND '08/31/11 00:00:00'
Therefore a punch on 08/31/2011 at 12:53 will not get included. I think this should work, and is a bit more elegant than adding a day to the end date...
SELECT * FROM `punches` WHERE DATE(`date`) BETWEEN '2011-08-20' AND '2011-08-31'