Where clause containing date in MySQL statement not working - mysql

Table Name: DemoTable.
Total Fields: 2
Fields:
id (int, auto increment, primary key)
month_and_year (varchar(10))
month_and_year contains date as '2015-03', '2015-01', '2014-12' and so on...
I am trying to get values from the table between '2014-10' and '2015-03'.
SELECT * FROM DemoTable where month_and_year>='2014-10' AND month_and_year<='2015-03' ORDER BY month_and_year DESC
Query does not give desired output as month_and_year field has varchar data type. Changing varchar to date data type isn't possible as date data type does not accept date in 'yyyy-mm' format.
How can the result be obtained?
PS:Is UNIX_TIMESTAMP() a safe bet in this case?

You should never store date value as varchar and choose mysql native date related data types like date,datetime or timestamp
However in your case you need to do some date related calculations before doing the select query. Consider the following table
mysql> select * from test ;
+------+----------------+
| id | month_and_year |
+------+----------------+
| 1 | 2014-10 |
| 2 | 2014-10 |
| 3 | 2014-09 |
| 4 | 2014-11 |
| 5 | 2015-01 |
| 6 | 2014-08 |
+------+----------------+
Now the approach would as
First convert the varchar to real date
Then for the lower limit always start the comparison from first day of the year month value
The upper limit will be till the end of the month.
So the query becomes
select * from test
where
date_format(
str_to_date(
month_and_year,'%Y-%m'
),'%Y-%m-01'
)
>=
date_format(
str_to_date('2014-10','%Y-%m'
),'%Y-%m-01'
)
and
last_day(
date_format(
str_to_date(month_and_year,'%Y-%m'
),'%Y-%m-01'
)
)
<=
last_day(
date_format(
str_to_date('2015-03','%Y-%m'
),'%Y-%m-01'
)
);
The output will be as
+------+----------------+
| id | month_and_year |
+------+----------------+
| 1 | 2014-10 |
| 2 | 2014-10 |
| 4 | 2014-11 |
| 5 | 2015-01 |
+------+----------------+

Use the function STR_TO_DATE(string,format);
http://www.mysqltutorial.org/mysql-str_to_date/

You should use either mysql date time functions or use int field in mysql and store UNIXTIMESTAMP and compare like you are already doing. I think it is overkill to store unixtimestamp because you only need month and year and you won't benefit a lot from unixtimestamp advantages.

Related

Inserting random data from a list

These are my table columns:
ID || Date || Description || Priority
My goal is to insert random test data of 2000 rows with date ranging between (7/1/2019 - 7/1/2020) and randomize the priority from list (High, Medium, Low).
I know how to insert random numbers but I am stuck with the date and the priority fields.
If I need to write code, any pointers on how do I do it?
Just want to be clear - I have issue with randomizing and inserting from a given list
CREATE TABLE mytable (
id SERIAL PRIMARY KEY,
date DATE NOT NULL,
description TEXT,
priority ENUM('High','Medium','Low') NOT NULL
);
INSERT INTO mytable (date, priority)
SELECT '2019-07-01' + INTERVAL FLOOR(RAND()*365) DAY,
ELT(1+FLOOR(RAND()*3), 'High', 'Medium', 'Low')
FROM DUAL;
The fake table DUAL is a special keyword. You can select from it, and it always returns exactly one row. But it has no real columns with data, so you can only select expressions.
Do this INSERT a few times and you get:
mysql> select * from mytable;
+----+------------+-------------+----------+
| id | date | description | priority |
+----+------------+-------------+----------+
| 1 | 2019-10-20 | NULL | Medium |
| 2 | 2020-05-17 | NULL | High |
| 3 | 2020-06-25 | NULL | Low |
| 4 | 2020-05-06 | NULL | Medium |
| 5 | 2019-09-30 | NULL | High |
| 6 | 2019-08-06 | NULL | Low |
| 7 | 2020-02-21 | NULL | High |
| 8 | 2019-11-10 | NULL | High |
| 9 | 2019-07-30 | NULL | High |
+----+------------+-------------+----------+
Here's a trick to use the number of rows in the table itself to insert the same number of rows, basically doubling the number of rows:
INSERT INTO mytable (date, priority)
SELECT '2019-07-01' + INTERVAL FLOOR(RAND()*365) DAY,
ELT(1+FLOOR(RAND()*3), 'High', 'Medium', 'Low')
FROM mytable;
Just changing FROM DUAL to FROM mytable I change from selecting one row, to selecting the current number of rows from the table. But the values I insert are still random expressions, not the values already in those rows. So I get new rows with new random values.
Then repeat this INSERT as many times as you want to double the number of rows.
Read also about the ELT() function.
You seem to be looking for something like this. A basic random sample is:
select t.*
from t
where date >= '2019-07-01' and date < '2020-07-01'
order by random()
fetch first 2000 rows only;
Of course, the function for random() varies by database, as does the logic for limiting rows. This should get about the same distribution of priorities as in the original data.
If you want the rows to come by priority first, then use:
select t.*
from t
where date >= '2019-07-01' and date < '2020-07-01'
order by (case when priority = 'High' then 1 when priority = 'Medium' then 2 else 3 end),
random()
fetch first 2000 rows only;

Group by day using the timestamp field

My table schema looks like this:
+--------------------+--------------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+--------------------+--------------+------+-----+-------------------+-----------------------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(50 | NO | | 0 | |
| modified | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| created | timestamp | NO | | CURRENT_TIMESTAMP | |
+--------------------+--------------+------+-----+-------------------+-----------------------------+
I want to get a count of the names and group by number of names modified by day at the moment I can only group by the full date including the timestamp eg:
SELECT name, count(*) FROM mytable GROUP BY modified
Thanks in advance.
Use MySQL DATE() function to extract the date from the timestamp:
SELECT name, count(*) FROM mytable GROUP BY DATE(mytable.modified);
The DATE() function extracts the date value from a date or datetime expression.
Dependant upon what you mean by day, you have a few options;
Here's your cheat sheet.
DAYNAME(date) for the day of the week (Mon-Sun)
DAYOFMONTH(date) for the day of the month (1-31)
DAYOFWEEK(date) for the day of the week (1-7)
DAYOFYEAR(date) for the day of the year (1-365)
Edit:
If you want to group by the entire date (as opposed to a particular day), ignoring the time you can use
DATE_FORMAT(date, format)
The full list of format specifiers can be found at the above link, but what you'll probably need is:
Date_FORMAT(date, '%Y-%m-%d')
This will format the date as 'YYYY-MM-DD' and you can group by that.
You can use this query or a version of it
SELECT DATE_FORMAT(modified,"%Y-%m-%d") as date_string, count(1) FROM mytable group by date_string;

Add a constant date column in mysql

i have a table in mysql.
+------+---------+
|value | unit |
+------+---------+
| 2 | DAY |
| 3 | MONTH |
+------+---------+
this is just a part of my table. it consists of many rows
i want to add a date column to this table with a constant date. say '2009-01-01'
type of the column should be date.
+------------+------+---------+
| date |value | unit |
+------------+------+---------+
| 2009-01-01 | 2 | DAY |
| 2009-01-01 | 3 | MONTH |
+------------+------+---------+
i want to create table_2
create table table_2 as
select value,unit,`dates` DATE NOT NULL DEFAULT '2009-01-01' from table;
but getting syntax error.
any ideas how to do it?
Try like this:
CREATE TABLE table_2(
dates DATE
) SELECT '2009-01-01' AS dates, value,
unit FROM table_1
for more information Visit here: http://dev.mysql.com/doc/refman/5.5/en/create-table-select.html

MySQL query date with offset given

In MySQL I have a table node_weather:
mysql> desc node_weather;
+--------------------+--------------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+--------------------+--------------+------+-----+-------------------+-----------------------------+
| W_id | mediumint(9) | NO | PRI | NULL | auto_increment |
| temperature | int(10) | YES | | NULL | |
| humidity | int(10) | YES | | NULL | |
| time | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
Now what I need to do is the following: for every two hours of the current day (00:00:00, 02:00:00, ..., 24:00:00) I want to get a temperature. Normally the query could be like that:
mysql> SELECT temperature
-> FROM node_weather
-> WHERE date(time) = DATE(NOW())
-> AND TIME(time) IN ('00:00:00','02:00:00','04:00:00','06:00:00','08:00:00','10:00:00','12:00:00','14:00:00','16:00:00','18:00:00','20:00:00','22:00:00','24:00:00');
In the ideal case, I should get a result as 12 rows selected and everything would be fine. But there are two problems with it:
The table does not include the data for thw whole day, so for example the temperature for the time '24:00:00' is missing. In this case, I would like to return NULL.
The table sometimes record the data with the timestamp like '10:00:02' or '09:59:58', but not '10:00:00'. To resolve this case, I would like to add the offset to all the values in IN expression (something like that ('10:00:00' - offset, '10:00:00' + offset)) and it would select always just ONE value (no matter which one) from this range.
I know it is kind of awkard, but that is how my boss wants it. Thanks for help!
Okay, a bit more precise than what I wrote in comments:
EDIT: Had a bug. Hopefully this doesn't.
SELECT
time,
deviation,
hour,
temperature
FROM (
SELECT
time,
ROUND(HOUR(time) / 2) * 2 AS hour,
IF(HOUR(time) % 2,
3600 - MINUTE(time) * 60 - SECOND(time),
MINUTE(time) * 60 + SECOND(time)
) AS deviation,
temperature
FROM node_weather
WHERE DATE(time) = DATE(NOW())
ORDER BY deviation ASC
) t
GROUP BY hour
ORDER BY
hour ASC
Basically, group on intervals like 09:00:00 - 10:59:59 (by rounding hour/2), then sort ascending by those intervals, and within the interval by the distance to the center of the interval (so we choose 10:00:00 over 09:00:00 or 10:59:59).

Change Mysql Column date format and Perform Query

For Example
select date_format(date(credit_date),'%Y-%m-%d') from product where date(credit_date) >= date '2012-11-02' and date(credit_date) <= date '2013-11-02'
How to Fetch the Column From Date1 To Date2
And Db Structure is
+-----------------------------------------+
| credit_date |
+-----------------------------------------+
| 21/09/2013 |
| 22/09/2013 |
| 23/09/2013 |
| 24/09/2013 |
| 25/09/2013 |
| 26/09/2013 |
| 27/09/2013 |
| 28/09/2013 |
+-----------------------------------------+
It look like your credit_date is a varchar type with another date format, if so try this:
select date_format(str_to_date(credit_date,'%d/%m/%Y'), '%Y-%m-%d') as dt
from product
where str_to_date(credit_date,'%d/%m/%Y') >= '2012-11-02'
and str_to_date(credit_date,'%d/%m/%Y') <= '2013-11-02'
The default format for mysql is Y-m-d you don't need to convert it on the where clause. Unless your database is configured to have a specific format. As your credit_date seems to be a varchar you have to convert it first to date then test it.
See it here on fiddle: http://sqlfiddle.com/#!2/8b379/9