Related
For example, if i have search string "2017-12-14" then i need to find all rows that matches 7-day range: "%-12-11", "%-12-12", "%-12-13", "%-12-14", "%-12-15", "%-12-16", "%-12-17".
Is it possible to do with MySql only?
To select same day cross years you can use following trick.
get the list of last 7 days/1 week NOW() - INTERVAL 1 WEEK
get the DAYOFYEAR of that days
search the database for all values of the same day in year
.
SELECT * FROM timevalues
WHERE DAYOFYEAR(timefield) IN (
SELECT DAYOFYEAR(timefield)
FROM timevalues
WHERE DATE(timefield) BETWEEN NOW() - INTERVAL 1 WEEK AND NOW()
)
;
Note: Leap year is not taken into calculation!
According to my brief investigation according to the leap year it would be easier to extend the SQL query with tolerance of 1 day, ie to use - INTERVAL 8 DAY instead of 7 and then control the validity of the day outside the database during processing the data in a loop.
Yes, it is possible.
The function you are looking for is +/- INTERVAL expr unit. See MySQL Date and Time Functions
So to get 7 days back use - INTERVAL 7 DAY:
SELECT *
FROM tablename
WHERE DATE(timefield) BETWEEN '2017-12-14' - INTERVAL 7 DAY AND '2017-12-14'
According to your example would be enough to use -INTERVAL 1 WEEK:
SELECT *
FROM tablename
WHERE DATE(timefield) BETWEEN '2017-12-14' - INTERVAL 1 WEEK AND '2017-12-14'
And List of all possible units
MICROSECOND SECOND MINUTE HOUR DAY WEEK MONTH QUARTER YEAR
SECOND_MICROSECOND MINUTE_MICROSECOND MINUTE_SECOND HOUR_MICROSECOND
HOUR_SECOND HOUR_MINUTE DAY_MICROSECOND DAY_SECOND DAY_MINUTE DAY_HOUR
YEAR_MONTH
I have a date column in my MySQL database. How do I get dayofquarter from this date?
I have been doing a datediff from the start of the quarter up till now, but would like to be able to do this dynamically.
You've got to do some calculation, but it can definitely be done dynamicly in MySQL alone. I'll use the date April 30, 2016 (2016-04-30) as in the example:
First, here is how you dynamically get the first day of a quarter:
SELECT makedate(YEAR("2016-04-30"), 1) + INTERVAL QUARTER("2016-04-30") QUARTER - INTERVAL 1 QUARTER
Once you have this, subtract it from the original date to get the day of quarter for the date and add 1 to it (or the first day would be day 0)
SELECT DATEDIFF("2016-04-30",(makedate( YEAR ("2016-04-30"), 1) + INTERVAL QUARTER("2016-04-30") QUARTER - INTERVAL 1 QUARTER)) + 1 AS dayofquarter
To be dynamic, replace all three 2016-04-30 dates with the date column in the table you're querying from:
SELECT DATEDIFF(`somedatecolumn`,(makedate( YEAR (`somedatecolumn`), 1) + INTERVAL QUARTER(`somedatecolumn`) QUARTER - INTERVAL 1 QUARTER)) + 1 AS dayofquarter FROM `my_table`
If you're looking for a simple, snazzy, built-in function like DAYOFQUARTER(somedate), your out of luck, you'll need to create your own http://dev.mysql.com/doc/refman/5.7/en/create-procedure.html
How would I go about writing a statement in MySQL to return the previous start and end date of the previous quarter? Say if I wanted the start and end date of the quarter before this one (i.e. beginning of last October and end of last December).
Try this one:
SELECT
MAKEDATE(YEAR(CURDATE()), 1) + INTERVAL QUARTER(CURDATE())-1 QUARTER - INTERVAL 1 DAY,
MAKEDATE(YEAR(CURDATE()), 1) + INTERVAL QUARTER(CURDATE())-2 QUARTER
I find it helpful to use this TRUNC_QUARTER stored function. It converts any date or date/time value into midnight on the first day of the calendar quarter in which it occurs. Then you can use INTERVAL arithmetic to manipulate it.
DELIMITER $$
DROP FUNCTION IF EXISTS TRUNC_QUARTER$$
CREATE
FUNCTION TRUNC_QUARTER(datestamp DATETIME)
RETURNS DATE DETERMINISTIC NO SQL
COMMENT 'returns preceding first of the quarter'
RETURN DATE(CONCAT(YEAR(datestamp),'-', 1 + 3*(QUARTER(datestamp)-1),'-01'))$$
DELIMITER ;
With it you can write:
SELECT TRUNC_QUARTER(CURDATE()) - INTERVAL 1 QUARTER start_last_quarter,
TRUNC_QUARTER(CURDATE()) - INTERVAL 1 DAY end_last_quarter
Begin and end of quarters are fixed, so there is no need to actually “calculate” those – we know they are January 1st, April 1st, etc, and March 31st, June 30th, etc. respectively.
So all that leaves us with is to get the correct year prepended to those fixed dates – if the current quarter is Q1, then go back one year, else use the current year.
QUARTER(NOW()) will give us the current quarter (from 1 to 4), so this could be as simple as this:
SELECT
CASE QUARTER(NOW())
WHEN 1 THEN DATE_FORMAT(NOW() - INTERVAL 1 YEAR, '%Y-10-01')
WHEN 2 THEN DATE_FORMAT(NOW(), '%Y-01-01')
WHEN 3 THEN DATE_FORMAT(NOW(), '%Y-04-01')
WHEN 4 THEN DATE_FORMAT(NOW(), '%Y-07-01')
END AS previous_quarter_begin,
CASE QUARTER(NOW())
WHEN 1 THEN DATE_FORMAT(NOW() - INTERVAL 1 YEAR, '%Y-12-31')
WHEN 2 THEN DATE_FORMAT(NOW(), '%Y-03-31')
WHEN 3 THEN DATE_FORMAT(NOW(), '%Y-06-30')
WHEN 4 THEN DATE_FORMAT(NOW(), '%Y-09-30')
END AS previous_quarter_end
http://sqlfiddle.com/#!9/9eecb/1858
If you want those dates in a different format, say mm/dd/yyyy instead, then you can simply change the format specified to 10/01/%Y etc.
(And if you want to test this, to see if it actually works correctly for different dates, then you can replace each occurrence of NOW() in the above query with a fixed date, like say '2015-12-22' to see if this will give the expected result for a date in December.)
This will work such that if the date is in the first quarter, it'll roll back to the previous year in quarter 4.
SELECT #dateLastQuarter := DATE_SUB('yourdate', INTERVAL 3 MONTH);
SELECT MAKEDATE(YEAR(#dateLastQuarter), 1) + INTERVAL QUARTER(#dateLastQuarter) QUARTER - INTERVAL 1 QUARTER,
MAKEDATE(YEAR(#dateLastQuarter), 1) + INTERVAL QUARTER(#dateLastQuarter) QUARTER - INTERVAL 1 DAY;
Suppose I have 2011-01-03 and I want to get the first of the week, which is sunday, which is 2011-01-02, how do I go about doing that?
The reason is I have this query:
select
YEAR(date_entered) as year,
date(date_entered) as week, <-------This is what I want to change to select the first day of the week.
SUM(1) as total_ncrs,
SUM(case when orgin = picked_up_at then 1 else 0 end) as ncrs_caught_at_station
from sugarcrm2.ncr_ncr
where
sugarcrm2.ncr_ncr.date_entered > date('2011-01-01')
and orgin in(
'Silkscreen',
'Brake',
'Assembly',
'Welding',
'Machining',
'2000W Laser',
'Paint Booth 1',
'Paint Prep',
'Packaging',
'PEM',
'Deburr',
'Laser ',
'Paint Booth 2',
'Toolpath'
)
and date_entered is not null
and orgin is not null
AND(grading = 'Minor' or grading = 'Major')
and week(date_entered) > week(current_timestamp) -20
group by year, week(date_entered)
order by year asc, week asc
And yes, I realize that origin is spelled wrong but it was here before I was so I can't correct it as too many internal apps reference it.
So, I am grouping by weeks but I want this to populate my chart, so I can't have all the beginning of weeks looking like different dates. How do I fix this?
If the week starts on Sunday do this:
DATE_ADD(mydate, INTERVAL(1-DAYOFWEEK(mydate)) DAY)
If the week starts on Monday do this:
DATE_ADD(mydate, INTERVAL(-WEEKDAY(mydate)) DAY);
more info
If you need to handle weeks which start on Mondays, you could also do it that way. First define a custom FIRST_DAY_OF_WEEK function:
DELIMITER ;;
CREATE FUNCTION FIRST_DAY_OF_WEEK(day DATE)
RETURNS DATE DETERMINISTIC
BEGIN
RETURN SUBDATE(day, WEEKDAY(day));
END;;
DELIMITER ;
And then you could do:
SELECT FIRST_DAY_OF_WEEK('2011-01-03');
For your information, MySQL provides two different functions to retrieve the first day of a week. There is DAYOFWEEK:
Returns the weekday index for date (1 = Sunday, 2 = Monday, …, 7 = Saturday). These index values correspond to the ODBC standard.
And WEEKDAY:
Returns the weekday index for date (0 = Monday, 1 = Tuesday, … 6 = Sunday).
If week starts on Monday
SELECT SUBDATE(mydate, weekday(mydate));
If week starts on Sunday
SELECT SUBDATE(mydate, dayofweek(mydate) - 1);
Example:
SELECT SUBDATE('2018-04-11', weekday('2018-04-11'));
2018-04-09
SELECT SUBDATE('2018-04-11', dayofweek('2018-04-11') - 1);
2018-04-08
Week starts day from sunday then get First date of the Week and Last date of week
SELECT
DATE("2019-03-31" + INTERVAL (1 - DAYOFWEEK("2019-03-31")) DAY) as start_date,
DATE("2019-03-31" + INTERVAL (7 - DAYOFWEEK("2019-03-31")) DAY) as end_date
Week starts day from Monday then get First date of the Week and Last date of week
SELECT
DATE("2019-03-31" + INTERVAL ( - WEEKDAY("2019-03-31")) DAY) as start_date,
DATE("2019-03-31" + INTERVAL (6 - WEEKDAY("2019-03-31")) DAY) as end_date
select '2011-01-03' - INTERVAL (WEEKDAY('2011-01-03')+1) DAY;
returns the date of the first day of week. You may look into it.
This is a much simpler approach than writing a function to determine the first day of a week.
Some variants would be such as
SELECT DATE_ADD((SELECT CURDATE() - INTERVAL (WEEKDAY(CURDATE())+1)DAY),INTERVAL 7 DAY) (for the ending date of a query, such as between "beginning date" and "ending date").
SELECT CURDATE() - INTERVAL (WEEKDAY(CURDATE())+1) DAY (for the beginning date of a query).
This will return all values for the current week. An example query would be as follows:
SELECT b.foo FROM bar b
WHERE b.datefield BETWEEN
(SELECT CURDATE() - INTERVAL (WEEKDAY(CURDATE())+1) DAY)
AND (SELECT DATE_ADD((SELECT CURDATE() - INTERVAL (WEEKDAY(CURDATE())+1)DAY),INTERVAL 7 DAY))
This works form me
Just make sure both dates in the below query are the same...
SELECT ('2017-10-07' - INTERVAL WEEKDAY('2017-10-07') Day) As `mondaythisweek`
This query returns: 2017-10-02 which is a monday,
But if your first day is sunday, then just subtract a day from the result of this and wallah!
If the week starts on Monday do this:
DATE_SUB(mydate, INTERVAL WEEKDAY(mydate) DAY)
SELECT MIN(DATE*given_date*) FROM *table_name*
This will return when the week started at for any given date.
Keep the good work going!
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.