mysql date_sub using a field as interval - mysql

I need help with mysql and date_sub(). I have a table call Activity
Activity(id,deadline,alert)
Activity(1,'2011-04-18','1 DAY');
Activity(2,'2011-04-13','1 MONTH');
Every row in A have an 'alert', this field indicate how time before the deadline an activity have to reported.
For example
On 2011-04-17 I have to report the activity with 'id' 1
On 2011-03-14 I have to report the activity with 'id' 2
I trying to use date_sub() functions, but I can't use a field as params of this function. Any idea how to fix this?
SELECT *
FROM `activities`
WHERE date_sub(`deadline`, INTERVAL alert) >= CURDATE();

Split the alert into 2 fields
Alert_count: integer
Alert_period: enum('hour','day','month','week')
And change the query like so:
SELECT *
FROM `activities`
WHERE CASE alert_period
WHEN 'hour' THEN date_sub(`deadline`, INTERVAL alert_count HOUR) >= CURDATE();
WHEN 'day' THEN date_sub(`deadline`, INTERVAL alert_count DAY) >= CURDATE();
...
END CASE

If the number of alerts is small, you could write out a case:
WHERE case
when alert = '1 DAY' then date_sub(`deadline`, INTERVAL 1 DAY)
when alert = '1 MONTH' then date_sub(`deadline`, INTERVAL 1 MONTH)
... etc ...
end >= CURDATE();

Although this solution will work it's not the most efficient way of storing this data because each time you query for this data MySQL must look at the interval value in every row, compute it against deadline date and then return you the answer.
If you were to compute this information just before you insert the data and store alert_date as a DATE column then (assuming you index it too) it'd be very fast for MySQL to find the rows with a query like:
SELECT id FROM activity WHERE alert=CURRENT_DATE();
even more efficient (it'd allow it to be query cached):
SELECT id FROM activity WHERE alert="2011-04-23";

Strings are not allowed after INTERVAL, you can convert your all alert limit to day on one column.
Activity(id,deadline,alert)
Activity(1,'2011-04-18','1');
Activity(2,'2011-04-13','30');
and use as:
SELECT *
FROM `activities`
WHERE date_sub(`deadline`, INTERVAL alert DAY) >= CURDATE();

Related

Sql Query, not retrieving correct values with CURDATE() function

I need to retrieve records from database where my 'dateOfTermination' value is equal to today's date.
I used the below query, but it won't show any results.
select * from user
where CRM_Status='pending' and dateOfTermination = DATE_ADD(CURDATE(), INTERVAL 1 DAY)
It will only work if the query is as below.
select * from user
where CRM_Status='pending' and dateOfTermination < DATE_ADD(CURDATE(), INTERVAL 1 DAY)
Is it because of an issue in date format?
My guess is that dateOfTermination has a time component. Try this:
select u.*
from user u
where u.CRM_Status = 'pending' and
u.dateOfTermination >= CURDATE() AND
u.dateOfTermination < DATE_ADD(CURDATE(), INTERVAL 1 DAY);
You can also express this as:
select u.*
from user u
where u.CRM_Status = 'pending' and
DATE(u.dateOfTermination) = DATE_ADD(CURDATE(), INTERVAL 1 DAY);
Actually, the semantics are slightly different -- but it is unclear what you really intend. The first version is "better" in the sense that it can better make use of indexes for performance.
You can use MySQL DATE_FORMAT function to get the date without the time component and then do the comparison. So the query should look like:
SELECT * FROM user
WHERE CRM_Status='pending' AND
DATE_FORMAT(dateOfTermination,'%d-%m-%Y')=DATE_FORMAT(DATE_ADD(CURDATE(),INTERVAL 1 DAY),'%d-%m-%Y');
Assuming that the time is the problem. Why not just keep it simple?
select * from user
where CRM_Status='pending'
and cast(dateOfTermination as date) = cast(GETDATE() as DATE)

mysql BETWEEN date range not working

I have a table called barcode_log, and these are all the datas from the table.
And now if I run this query
SELECT * FROM `barcode_log` WHERE barcode_log.assign_time BETWEEN DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY) AND CURRENT_DATE;
I get this result
But it should return all the rows as all the data is within this month only. And assign_time field is stored as datetime. Any idea what i am doing wrong??
You are ignoring the time part (hh:mm:ss).
If the end day is set to the end timestamp of the current date then you can get the data of current day's too.
BETWEEN is inclusive
SELECT
*
FROM
`barcode_log`
WHERE
barcode_log.assign_time BETWEEN DATE_SUB(
CURRENT_DATE,
INTERVAL 30 DAY
)
AND TIMESTAMP(CONCAT(CURDATE(),' ','23:59:59'));
While the accepted answer works, there is a simpler solution. Just take the date part of the datetime column:
SELECT
*
FROM
`barcode_log`
WHERE
DATE(barcode_log.assign_time)
BETWEEN DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY) AND CURRENT_DATE;
There is another way around: CAST() on barcode_log.assign_time field.
SELECT *
FROM `barcode_log`
WHERE CAST(barcode_log.assign_time AS DATE)
BETWEEN DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY) AND CURRENT_DATE;
This excludes time from comparison and works fine for your purpose.

getting mysql dates 3 days earlier when all dates in timestamp format

I have all dates stored as timestamps (int) in the database.
how can I get dates that are exactly 3 days earlier?
I tried
SELECT date from user WHERE DATE_ADD(DATE( FROM_UNIXTIME( `created` ) ), INTERVAL 3 DAY) = CURDATE()
is that the best/most efficient way to do it?
i think the database prefer to only do the date add 2 times to define the range, like:
SELECT date FROM user
WHERE UNIX_TIMESTAMP(DATE_ADD(CURDATE(), INTERVAL -3 DAY)) <= `created`
AND `created` < UNIX_TIMESTAMP(DATE_ADD(CURDATE(), INTERVAL -2 DAY));
Test putting DESCRIBE keyword before SELECT in both case, and the database respond with how its going to perform the query
SELECT date
FROM user
WHERE created = UNIX_TIMESTAMP(CURRENT_DATE - INTERVAL 3 DAY)
Note: no function used on the created column in where clause. This query should be able to use index.

How to get first day of every corresponding month in mysql?

I want to get first day of every corresponding month of current year. For example, if user selects '2010-06-15', query demands to run from '2010-06-01' instead of '2010-06-15'.
Please help me how to calculate first day from selected date. Currently, I am trying to get desirable using following mysql select query:
Select
DAYOFMONTH(hrm_attendanceregister.Date) >=
DAYOFMONTH(
DATE_SUB('2010-07-17', INTERVAL - DAYOFMONTH('2010-07-17') + 1 DAY
)
FROM
hrm_attendanceregister;
Thanks
Is this what you are looking for:
select CAST(DATE_FORMAT(NOW() ,'%Y-%m-01') as DATE);
You can use the LAST_DAY function provided by MySQL to retrieve the last day of any month, that's easy:
SELECT LAST_DAY('2010-06-15');
Will return:
2010-06-30
Unfortunately, MySQL does not provide any FIRST_DAY function to retrieve the first day of a month (not sure why). But given the last day, you can add a day and subtract a month to get the first day. Thus you can define a custom function:
DELIMITER ;;
CREATE FUNCTION FIRST_DAY(day DATE)
RETURNS DATE DETERMINISTIC
BEGIN
RETURN ADDDATE(LAST_DAY(SUBDATE(day, INTERVAL 1 MONTH)), 1);
END;;
DELIMITER ;
That way:
SELECT FIRST_DAY('2010-06-15');
Will return:
2010-06-01
There is actually a straightforward solution since the first day of the month is simply today - (day_of_month_in_today - 1):
select now() - interval (day(now())-1) day
Contrast that with the other methods which are extremely roundabout and indirect.
Also, since we are not interested in the time component, curdate() is a better (and faster) function than now(). We can also take advantage of subdate()'s 2-arity overload since that is more performant than using interval. So a better solution is:
select subdate(curdate(), (day(curdate())-1))
This is old but this might be helpful for new human web crawlers XD
For the first day of the current month you can use:
SELECT LAST_DAY(NOW() - INTERVAL 1 MONTH) + INTERVAL 1 DAY;
You can use EXTRACT to get the date parts you want:
EXTRACT( YEAR_MONTH FROM DATE('2011-09-28') )
-- 201109
This works well for grouping.
You can use DATE_FORMAT() function in order to get the first day of any date field.
SELECT DATE_FORMAT(CURDATE(),'%Y-%m-01') as FIRST_DAY_CURRENT_MONTH
FROM dual;
Change Curdate() with any other Date field like:
SELECT DATE_FORMAT(purchase_date,'%Y-%m-01') AS FIRST_DAY_SALES_MONTH
FROM Company.Sales;
Then, using your own question:
SELECT *
FROM
hrm_attendanceregister
WHERE
hrm_attendanceregister.Date) >=
DATE_FORMAT(CURDATE(),'%Y-%m-01')
You can change CURDATE() with any other given date.
There are many ways to calculate the first day of a month, and the following are the performance in my computer (you may try this on your own computer)
And the winner is LAST_DAY(#D - interval 1 month) + interval 1 day
set #D=curdate();
select BENCHMARK(100000000, subdate(#D, (day(#D)-1))); -- 33 seconds
SELECT BENCHMARK(100000000, #D - INTERVAL (day(#D) - 1) DAY); -- 33 seconds
SELECT BENCHMARK(100000000, cast(DATE_FORMAT(#D, '%Y-%m-01') as date)); -- 29 seconds
SELECT BENCHMARK(100000000, LAST_DAY(#D - interval 1 month) + interval 1 day); -- 26 seconds
I'm surprised no one has proposed something akin to this (I do not know how performant it is):
CONCAT_WS('-', YEAR(CURDATE()), MONTH(CURDATE()), '1')
Additional date operations could be performed to remove formatting, if necessary
use date_format method and check just month & year
select * from table_name where date_format(date_column, "%Y-%m")="2010-06"
SELECT LAST_DAY(date) as last_date, DATE_FORMAT(date,'%Y-%m-01') AS fisrt_date FROM table_name
date=your column name
The solutions that use last_day() and then add/subtract a month and a day are not interchangeable.
Example:
date_sub(date_add(last_day(curdate()), interval 1 day), interval 3 month)
always works for any supplied number of months you want to go back
date_add(date_sub(last_day(now()), interval 3 month), interval 1 day)
will fail in some cases, for instance if your current month has 30 days and the month you're subtracting back to (and then adding a day) has 31.
date_add(subdate(curdate(), interval day(?) day), interval 1 day)
change the ? for the corresponding date
This works fine for me.
date(SUBDATE("Added Time", INTERVAL (day("Added Time") -1) day))
** replace "Added Time" with column name
Use Cases:
If you want to reset all date fields except Month and Year.
If you want to retain the column format as "date". (not as "text" or "number")
Slow (17s):
SELECT BENCHMARK(100000000, current_date - INTERVAL (day(current_date) - 1) DAY);
SELECT BENCHMARK(100000000, cast(DATE_FORMAT(current_date, '%Y-%m-01') as date));
If you don't need a date type this is faster:
Fast (6s):
SELECT BENCHMARK(100000000, DATE_FORMAT(CURDATE(), '%Y-%m-01'));
SELECT BENCHMARK(100000000, DATE_FORMAT(current_date, '%Y-%m-01'));
select big.* from
(select #date := '2010-06-15')var
straight_join
(select * from your_table where date_column >= concat(year(#date),'-',month(#date),'-01'))big;
This will not create a full table scan.

Select mysql query between date?

How to select data from mysql table past date to current date? For example, Select data from 1 january 2009 until current date ??
My column "datetime" is in datetime date type. Please help, thanks
Edit:
If let say i want to get day per day data from 1 january 2009, how to write the query? Use count and between function?
select * from *table_name* where *datetime_column* between '01/01/2009' and curdate()
or using >= and <= :
select * from *table_name* where *datetime_column* >= '01/01/2009' and *datetime_column* <= curdate()
All the above works, and here is another way if you just want to number of days/time back rather a entering date
select * from *table_name* where *datetime_column* BETWEEN DATE_SUB(NOW(), INTERVAL 30 DAY) AND NOW()
You can use now() like:
Select data from tablename where datetime >= "01-01-2009 00:00:00" and datetime <= now();
Late answer, but the accepted answer didn't work for me.
If you set both start and end dates manually (not using curdate()), make sure to specify the hours, minutes and seconds (2019-12-02 23:59:59) on the end date or you won't get any results from that day, i.e.:
This WILL include records from 2019-12-02:
SELECT *SOMEFIELDS* FROM *YOURTABLE* where *YOURDATEFIELD* between '2019-12-01' and '2019-12-02 23:59:59'
This WON'T include records from 2019-12-02:
SELECT *SOMEFIELDS* FROM *YOURTABLE* where *YOURDATEFIELD* between '2019-12-01' and '2019-12-02'