The column has a start and end date
month_name
23 March, 2018 - 23 April, 2018
23 March, 2018 is the start date and 23 April, 2018 is the end date
How can I use them as to the start date and end date to query?
You would need to use SUBSTRING_INDEX to return a part of the string to the left or right of the hyphen. But this would be terrible in terms of performance. So you need to look at your data structure and redesign accordingly. The start and end dates should be in distinct columns with an INDEX and appropriate DATATYPE set (DATETIME, TIMESTAMP, DATE).
I would suggest that you process the text prior to saving to the database, by using client language regex or split/substring functionality to correctly format the dates into MYSQL format before saving.
set #fromto='23 March, 2018 - 23 April, 2018';
select
str_to_date(left(#fromto,locate('-',#fromto)-1),'%d %M,%Y') datefrom,
str_to_date(right(#fromto,length(#fromto)-locate('-',#fromto)),'%d %M,%Y') dateto;
output:
+------------+------------+
| datefrom | dateto |
+------------+------------+
| 2018-03-23 | 2018-04-23 |
+------------+------------+
short explanation:
set #fromto - defines a variable, which is used as input for this example
locate('-',#fromto) - this will find the length of the part in #fromto before the '-', the -1 is needed because where only want the part before the '-'
length(#fromto)-locate('-',#fromto) - this will find the length of the part in #fromto after the '-'
str_to_date(...) - see STR_TO_DATE
For each and every query that would need to use these dates, you would have to unpick one or both of these dates that are relevant to the query using this kind of text and date manipulation
SELECT .....
WHERE whatever_else
AND STR_TO_DATE(SUBSTRING_INDEX(monthname, ' -', 1 ), '%d %M,%Y') = '2018-03-23'
AND STR_TO_DATE(SUBSTRING(monthname, INSTR(monthname, '- ') +2 ), '%d %M,%Y') = '2018-04-23'
In short your queries would be a complete nightmare to write and maintain and any indexing benefits you might have been able to use had these 2 dates been saved in 2 seperate columns are completely lost.
SUBSTRING_INDEX()
SUBSTRING()
INSTR()
STR_TO_DATE()
Related
I am trying to use TIMESTAMPDIFF function in one of my queries and is making an headache for me.
TABLE
id | web_address | timeperiod | timeperiod_exp
1 | www.google.com | 1564692614 | 1564779014
1564692614 = GMT: Thursday, August 1, 2019 8:50:14 PM
1564779014 = GMT: Friday, August 2, 2019 8:50:14 PM
WHATS THE PROBLEM ?
As one can see the difference between these two timestamps is exactly 1 day but is returning no records.
SELECT * FROM mytable WHERE TIMESTAMPDIFF(DAY, timeperiod, timeperiod_exp) >= 1
WHERE IS THE FIDDLE ?
https://www.db-fiddle.com/f/udmrC2xdvrEEKGxEF7ty84/7
WHAT SHOULD BE DONE ?
Please take a look at the fiddle above and suggest what should be modified or other function in place of timestampdiff.
Look at the documentation for TIMESTAMPDIFF()
TIMESTAMPDIFF(unit,datetime_expr1,datetime_expr2)
Returns datetime_expr2 − datetime_expr1, where datetime_expr1 and
datetime_expr2 are date or datetime expressions. One expression may be
a date and the other a datetime
As you see, it expects the parameters to be of type DATE or DATETIME. But you have your timestamps stored as integers.
So either use FROM_UNIXTIME() to convert your integer timestamps to DATETIME:
SELECT *
FROM mytable
WHERE TIMESTAMPDIFF(DAY, FROM_UNIXTIME(timeperiod), FROM_UNIXTIME(timeperiod_exp)) >= 1
db-fiddle
Or just use simple arithmetics (since we know how many seconds are in one day):
SELECT *
FROM mytable
WHERE (timeperiod_exp - timeperiod) >= 60*60*24
db-fiddle
As if i see the function TIMESTAMPDIFF() should take two timestamps but it is taking dates instead of direct timestamps in integers Thus the following works:
SELECT * FROM mytable WHERE TIMESTAMPDIFF(DAY, FROM_UNIXTIME(timeperiod), FROM_UNIXTIME(timeperiod_exp)) >= 1
Updated Fiddle
https://www.db-fiddle.com/f/udmrC2xdvrEEKGxEF7ty84/8
I have a legacy table which has a varchar column represent date, format is MM/DD/YYYY (e.g. 01/08/2015). It is not convenient to perform data range selection since it is a varchar (when I use < or > kinds comparison, it goes to varchar/string comparison, which have different results from date comparision).
For example, I want to select only rows which dates are between 01/08/2015 and 01/10/2015. Any smart solution is appreciated, and I cannot change the data type of varchar to date in my existing table.
I am using MySQL Workbench/MySQL.
Varchar dates are evil and they are not real date, the best solution is to use mysql's native date data types.
Since you can't change the datatype you may use str_to_date() function and here how it works
mysql> select str_to_date('01/08/2015','%d/%m/%Y') as d ;
+------------+
| d |
+------------+
| 2015-08-01 |
+------------+
So the query for select would be
select * from table_name
where
str_to_date(date_column,'%d/%m/%Y')
between
str_to_date('01/08/2015','%d/%m/%Y')
and
str_to_date('01/10/2015','%d/%m/%Y')
There are many answers which addresses many different way of converting the string to date.
You may choose whichever is perfect for your need
SELECT * FROM `your_table` WHERE DATE_FORMAT(my_column_with_the_string_date, "%Y-%m-%d") <= '2011-09-30'
DATE_FORMAT can be used to convert your date string to any format: I will use the NOW() function instead of string to list different
formats that are supported
DATE_FORMAT(NOW(),'%b %d %Y %h:%i %p')
DATE_FORMAT(NOW(),'%m-%d-%Y')
DATE_FORMAT(NOW(),'%d %b %y')
DATE_FORMAT(NOW(),'%d %b %Y %T:%f')
The output of the above is:
Nov 04 2014 11:45 PM
11-04-2014
04 Nov 14
04 Nov 2014 11:45:34:243
You can modify your query accordingly
You can cast your dates as strings using STR_TO_DATE:
STR_TO_DATE(yourdatefield, '%m/%d/%Y')
SELECT STR_TO_DATE(got_fired_at, '%m/%d/%Y') BETWEEN ? AND ? FROM firings;
(field/table names guaranteed to have been chosen randomly)
Use MySQL's STR_TO_DATE function to parse the date strings to date objects then do the comparison.
my mysql database tb_date (varchar 20):
16 November 2014
06 December 2014
01 April 2014
12 April 2015
I want select between 01 January 2014 until 31 December 2014, how the query is with date conversion?
thanks..
This is an anti-pattern, storing date values in VARCHAR columns, rather than using datatypes specifically designed and implemented for storing date values... DATE, DATETIME or TIMESTAMP.
To answer your question, before it gets closed, you could use the STR_TO_DATE function to convert the strings into DATE datatype, and then do the comparison. MySQL won't be able to make use of an index range scan operation, it will need to evaluate that function on every flipping row in the table.
As an example:
SELECT t.mycol
FROM mytable t
WHERE STR_TO_DATE(t.mycol,'%d %M %Y') >= '2014-01-01'
AND STR_TO_DATE(t.mycol,'%d %M %Y') < '2015-01-01'
We'll need to check the MySQL Reference Manual to verify that '%M' is the right format specifier for the full month name...
http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_date-format
Yes, it looks like I guessed right. M is the month name.
As I already commented, you should store your date as Timestamp or Data format then you could simply compare.
However, there is still a solution.. You can convert the varchar to a date directly in your query :
select * from yourTable
where (str_to_date(tb_date, '%d %M %Y') between '2014-01-01' and '2014-12-31');
But please don't use this hack and change your date format...
Edit : If you are really willing to use varchar to store your date, change it to varchar(17) which is the max character possible using your string format.
I've got a terrible database on a project and they've used a text field for dates.
So, I need to build a view that has only the year in one column. The problem is that I have dates with any standard format like:
01-01-2012
01.01.2012
01 01 2012
1/1/2012
01/2012
1/2012
2012
01.2012
Is there any way to build an SQL (MySQL) to get only those 4 year digits to build a view?
Thanks a lot for your help!
It really depends on the whole data structure, you can use REGEX or String functions.
For example, with your sample data the last 4 digits on the right are the year so using
SELECT RIGHT(fieldname, 4) FROM table
would work. If that pattern doesn't work then you've either got to use concat and start splitting them or write a REGEX statement.
If RIGHT will work then you can do an INSERT SELECT
INSERT INTO table (yearcolumn)
SELECT RIGHT(fieldname, 4) FROM table
You can use REGEXP matching, to get rows from given year. There's no way to get a capture from regular expression though.
However, if the year part is alwayst last 4 digits, use RIGHT(). Otherwise, you will need to do reformatting client-side.
This may also help. This is Oracle query for the whole current year. It can be easily converted to any SQL. It uses recursive query to build annual table. Replace SYSDATE and Oracle formats with your version of SQL formats and system date:
WITH data(r, start_date) AS
(
SELECT 1 r, TRUNC(SYSDATE, 'YEAR') start_date FROM dual -- start_date: 1/1/2013
UNION ALL
SELECT r+1, TRUNC(SYSDATE, 'YEAR')+r-1 FROM data WHERE r < 365 -- any number: end_date - start_date or get the number of days in your year your way...
)
SELECT start_date
, TO_CHAR(start_date, 'YYYY') curr_year
, TRUNC(start_date, 'IW') wk_starts
, TRUNC(start_date, 'IW') + 7 - 1/86400 wk_ends
, TO_NUMBER (TO_CHAR (start_date, 'IW')) ISO_wk#
FROM data
/
START_DATE CURR_YEAR WK_STARTS WK_ENDS ISO_WK#
-----------------------------------------------------------------------
1/1/2013 2013 12/31/2012 1/6/2013 11:59:59 PM 1
1/1/2013 2013 12/31/2012 1/6/2013 11:59:59 PM 1
...
12/28/2013 2013 12/23/2013 12/29/2013 11:59:59 PM 52
12/29/2013 2013 12/23/2013 12/29/2013 11:59:59 PM 52
12/30/2013 2013 12/30/2013 1/5/2014 11:59:59 PM 1
I have a table with the following columns:
|start_date |TZ |
|Dec 2, 2012 |Eastern |
|Dec 2, 2012 |GMT |
Note 1: our server is in UTC time.
Note 2:The column start_date is a date field, not a timestamp field. Dec 2nd 2012 implicitly means "2012-12-02 00:00:00"
Note 3: The above table is actually multiple normalized tables, but for simplicity, I de-normalized it.
Note 4: I can put anything into the TZ table to make this easy.
I would like to select from my_table where start_date <= now()
However, this doesn't work because of timezone. If the current date/time is
Dec 1st Eastern at 9PM (which is Dec 2nd 1AM UTC), the above query will return both results,
but I really only want the 2nd one. This is further complicated by daylight savings.
Ideally, I would like a query that does the following:
select * from my_table where convert_to_utc_timestamp(start_date,tz) <= now()
The above method would convert start_date to a timestamp and then convert it to the right timezone.
How would I do this in SQL?
There are two functions you'll probably find useful.
The first is:
STR_TO_DATE(start_date,'%M %d,%Y')
That will get your string, in the specified format, converted to a MySQL DATE datatype.
If you have the mysql.time_zone_name et al. tables populated, you can use the function:
CONVERT_TZ()
(need to check that CONVERT_TZ takes a DATE and will return a DATETIME or TIMESTAMP, or include a time component in the string being converted to get a DATETIME, e.g.
STR_TO_DATE( CONCAT(start_date,' 00:00:00'),'%M %d,%Y %T')
Wrap that expression in the CONVERT_TZ() function, e.g.
CONVERT_TZ( datetime_expr ,'US/Eastern','GMT')
To make use of the values stored in your TZ column, those are going to need to match, or you need to come up with a way to match to, the values stored in the mysql.time_zone_name table.