CREATE TABLE `sport_data` (
`id` int(255) NOT NULL,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`sport` varchar(255) NOT NULL,
`musclePlan` varchar(255) NOT NULL,
`sport_time` varchar(255) NOT NULL,
`kcal` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
How can i get all data from this table from the last week (from Monday to Sunday)?
I have tried:
WHERE date >= curdate() - INTERVAL DAYOFWEEK(curdate())+5 DAY AND date < curdate() - INTERVAL DAYOFWEEK(curdate())-2 DAY
I don't know if this is correct that way?
Thanks in advance.
The >= and < pattern is what we usually use. That part looks right.
I think the question is about the expressions that returning the range start and end values.
I suggest that we test those expressions for a variety of date values, not just CURDATE(). We can use a value in place of CURDATE(), and check the results, and do that for a series of date values.
Conveniently, those expressions will evaluate the same in a SELECT list as they do in a WHERE clause. So we can run a SELECT statement, and check the results.
For example:
SELECT t.dt AS dt
, t.dt - INTERVAL DAYOFWEEK(t.dt)+5 DAY AS _ge
, t.dt - INTERVAL DAYOFWEEK(t.dt)-2 DAY AS _lt
FROM (
SELECT CURDATE() + INTERVAL 0 DAY AS dt
UNION ALL SELECT CURDATE() + INTERVAL -1 DAY
UNION ALL SELECT CURDATE() + INTERVAL -2 DAY
UNION ALL SELECT CURDATE() + INTERVAL -3 DAY
UNION ALL SELECT CURDATE() + INTERVAL -4 DAY
UNION ALL SELECT CURDATE() + INTERVAL -5 DAY
UNION ALL SELECT CURDATE() + INTERVAL -6 DAY
UNION ALL SELECT CURDATE() + INTERVAL -7 DAY
UNION ALL SELECT CURDATE() + INTERVAL -8 DAY
UNION ALL SELECT CURDATE() + INTERVAL -9 DAY
UNION ALL SELECT CURDATE() + INTERVAL -10 DAY
) t
If the expressions are returning the values we expect, in accordance with the specification, for each possible date value, then the expressions are right.
If the expressions are returning values that don't meet the spec, then we need to make adjustments. Note that an expression that "works" on a Wednesday date might not "work" on a Sunday date.)
DEMO: Showing 3 approaches and why current doesn't work.
If we assume by "last week" you mean the last full week Monday - Sunday of a week prior to the day you're presently on...
So if today was 20180422, you'd want 20180409-20180415
SELECT *
FROM SO50026532_sport_data
CROSS JOIN (SELECT #Today:=curdate()) z
WHERE date >= #today - interval (6 + case when dayofweek(#today)=1 then 7 else dayofWeek(#today)-1 end) day
and date <=#today - interval (case when dayofweek(#today)=1 then 7 else dayofWeek(#today)-1 end) day;
Or if your a fan of the >= and < then
SELECT *
FROM SO50026532_sport_data
CROSS JOIN (SELECT #Today:=curdate()) z
WHERE date >= #today - interval (6 + case when dayofweek(#today)=1 then 7 else dayofWeek(#today)-1 end) day
and date <#today - interval (case when dayofweek(#today)=1 then 7 else dayofWeek(#today)-1 end-1) day;
in the 2nd example we had to subtract by 1 since dayofweek isn't a 0 based. Of course I could have just date shifted everything down 2 and set sunday to 6... then I wouldn't' need to subtract by 1. and then we'd be adding 7 instead of 6 on the 1st part of the where. (demo has these 3 and your initial example showing what happens on 4/22.
Dayofweek starts on Sunday being 1. So I use a case statement to shift 1 to 7 and and all the others down 1 giving us Monday = 1 and sunday = 7
The cross join to derived table z was so I could control the curdate() easier and test. You could replace the variable with curdate() if you want and eliminate the cross join and derived table.
The first where clause subtracts 6 days (1 week and then the # of days from current date back to monday. This ensures we always start 1 week back from current date and on a monday. then we only get dates to the Sunday of that week.
Related
Need to return all records from "first day" of the current month & year? (ex.. need all 11/01 records)
Something like this:
(YEAR(INVOICE_DATE) = YEAR(NOW())
AND
(DAY(INVOICE_DATE) = “Current Month 11/01”
PS: I need the Year & Day values to be dynamic in the query.
INVOICE_DATE is a Date/Time type
Something like this would work:
SELECT *
FROM table
WHERE CONCAT(
YEAR(dateColumn),
MONTH(dateColumn),
'01'
) = CONCAT(
YEAR(NOW()),
MONTH(NOW()),
'01'
)
My preference would be to reference the bare column, which will allow MySQL to make use of a range scan operation with a suitable index
FROM t
WHERE t.invoice_date >= DATE_FORMAT(NOW(),'%Y-%m-01') + INTERVAL 0 DAY
AND t.invoice_date < DATE_FORMAT(NOW(),'%Y-%m-01') + INTERVAL 1 DAY
We can test the expressions (on the right side of the comparison operators), in a SELECT statement
SELECT DATE_FORMAT(NOW(),'%Y-%m-01') + INTERVAL 0 DAY AS bdt
, DATE_FORMAT(NOW(),'%Y-%m-01') + INTERVAL 1 DAY AS edt
return:
bdt edt
---------- ----------
2019-11-01 2019-11-02
and see that the net effect is the same as if we had written:
FROM t
WHERE t.invoice_date >= '2019-11-01 00:00:00'
AND t.invoice_date < '2019-11-02 00:00:00'
FOLLOWUP
Q: When I tried it, it returned 0 records? It might be the "TIME" portion of my DATE/TIME field that is causing it not to match/return any records?
A: Doing the comparisons as shown in the query above, with datetime greater than or equal to midnight of the first, and datetime less than midnight of the second, that should return datetime values anytime on the first.
datetime values like this would satisfy the condition: '2019-11-01 08:15', '2019-11-01 16:20', etc.
We can verify with simple test. We expect two of these datatime values to be returned, and the third to be excluded:
demonstration:
SELECT t.*
FROM ( SELECT '2019-11-01 08:15' + INTERVAL 0 DAY AS invoice_date
UNION ALL SELECT '2019-11-01 16:20' + INTERVAL 0 DAY
UNION ALL SELECT '2019-11-02 00:00' + INTERVAL 0 DAY
) t
WHERE t.invoice_date >= DATE_FORMAT(NOW(),'%Y-%m-01') + INTERVAL 0 DAY
AND t.invoice_date < DATE_FORMAT(NOW(),'%Y-%m-01') + INTERVAL 1 DAY
returns:
invoice_date
-------------------
2019-11-01 08:15:00
2019-11-01 16:20:00
Before we muck with expressions to generate the date boundary values, we should test with literals, e.g. '2019-11-02'.
FROM t
WHERE t.invoice_date >= '2019-11-01' + INTERVAL 0 DAY
AND t.invoice_date < '2019-11-02' + INTERVAL 0 DAY
Once we get that working, then we can work on developing expressions to replace the literals.
There are a method with SQL to SELECT from one database the date records where the date is today and the date is multiple of two years.
For example, i have a table call "list". That table have two column, 'ID' and 'last_date'. One of this record is: ID = '1' and date = '17-03-2015'
I need to select all record where the date is the date on the table + 2 year. For example today the query will return the ID 1.
Thanks to all.
Use DATE_SUB() to subtract 2 years from today's date, and compare that to the column.
SELECT id
FROM list
WHERE last_date = DATE_SUB(CURDATE(), INTERVAL 2 YEAR);
This is a little better than #Teja's solution because it only has to do the date arithmetic once, rather than for every row in the table. And if there's an index on the last_date column, it will be able to use it to find the rows quickly.
We can write an expression that returns a date value that is exactly two days before today's date:
SELECT DATE(NOW()) + INTERVAL -2 YEAR
We can use an expression in the WHERE clause of a query. If the column in the table we want to check is defined as DATE datatype:
SELECT t.id
FROM mytable t
WHERE t.mydatecol = DATE(NOW()) + INTERVAL -2 YEAR
If it's defined as a DATETIME, the normal pattern would be range check
SELECT t.id
FROM mytable t
WHERE t.mydatecol >= DATE(NOW()) + INTERVAL -2 YEAR
AND t.mydatecol < DATE(NOW()) + INTERVAL -2 YEAR + INTERVAL 1 DAY
If the column is stored as a VARCHAR in a non-canonical format e.g. DD-MM-YYYY then we could either attempt to convert that to a DATE using STR_TO_DATE (which we don't like to do because the query can't make effective use of a index), or we could convert our generated date value into the required string format for an equality comparison:
SELECT t.id
FROM mytable t
WHERE t.ddmmyyyy = DATE_FORMAT(DATE(NOW()) + INTERVAL -2 YEAR,'%d-%m-%Y')
That would get us exact match to '17-03-2015', but not to '17-3-2015'. And we have to do equality test or IN list, we can't do range check, because the value stored in the column isn't canonical.
If we need to look for multiple dates... today, two years ago, four years ago, six years ago, ... we can generate a list of dates and perform a join operation. (Assuming that mydatecol is defined as DATETIME...)
SELECT t.id
FROM ( SELECT DATE(NOW()) + INTERVAL 0 YEAR AS dt
UNION ALL SELECT DATE(NOW()) + INTERVAL -2 YEAR
UNION ALL SELECT DATE(NOW()) + INTERVAL -4 YEAR
UNION ALL SELECT DATE(NOW()) + INTERVAL -6 YEAR
UNION ALL SELECT DATE(NOW()) + INTERVAL -8 YEAR
UNION ALL SELECT DATE(NOW()) + INTERVAL -10 YEAR
UNION ALL SELECT DATE(NOW()) + INTERVAL -12 YEAR
UNION ALL SELECT DATE(NOW()) + INTERVAL -14 YEAR
UNION ALL SELECT DATE(NOW()) + INTERVAL -16 YEAR
UNION ALL SELECT DATE(NOW()) + INTERVAL -18 YEAR
UNION ALL SELECT DATE(NOW()) + INTERVAL -20 YEAR
) l
JOIN mytable t
WHERE t.mydatecol >= l.dt + INTERVAL 0 DAY
AND t.mydatecol < l.dt + INTERVAL 1 DAY
I want to get the three working days from the current date as excluding Saturday and Sunday. can any one help me out here.
I have tried the interval method and DayOfWeek(day) <> 1 AND DayOfWeek(day) <> 7 but it is not giving me the proper result
Not very elegant but
select d
from
(
select curdate() as d
union all
select curdate() + interval 1 day
union all
select curdate() + interval 2 day
union all
select curdate() + interval 3 day
union all
select curdate() + interval 4 day
) tmp
where dayofweek(d) not in (1,7)
order by d
limit 3
Is it possible to query for all dates in the future that are an increment of x days?
i.e.
SELECT *
FROM bookings
WHERE date >= CURDATE()
AND
(
date = CURDATE() + INTERVAL 6 DAY
OR date = CURDATE() + INTERVAL 12 DAY
OR date = CURDATE() + INTERVAL 18 DAY
etc.
)
Something like:
SELECT
*
FROM table
WHERE
date >= CURDATE()
AND
DATEDIFF(CURDATE(), date) % 6 = 0
Datediff returns the number of days difference, and % 6 says return the remainder when divided by six.
Yes.
Your logic is flawed, though. You probably meant
SELECT *
FROM table
WHERE
date = CURDATE() + INTERVAL 6 DAY
OR date = CURDATE() + INTERVAL 12 DAY
OR date = CURDATE() + INTERVAL 18 DAY
And don't use table names like "table" and field names like "date" (i.e. reserved words).
I found the following code to help in creating a weekly report based on a start date of Friday. The instructions say to replace ".$startWeekDay." with a 4. When I put '".$startDay."' as '2013-01-30', I get errors.
Also I get a report by day rather than week as I desire.
SELECT SUM(cost) AS total,
CONCAT(IF(date - INTERVAL 6 day < '".$startDay."',
'".$startDay."',
IF(WEEKDAY(date - INTERVAL 6 DAY) = ".$startWeekDay.",
date - INTERVAL 6 DAY,
date - INTERVAL ((WEEKDAY(date) - ".$startWeekDay.")) DAY)),
' - ', date) AS week,
IF((WEEKDAY(date) - ".$startWeekDay.") >= 0,
TO_DAYS(date) - (WEEKDAY(date) - ".$startWeekDay."),
TO_DAYS(date) - (7 - (".$startWeekDay." - WEEKDAY(date)))) AS sortDay
FROM daily_expense
WHERE date BETWEEN '".$startDay."' AND '".$endDay."'
GROUP BY sortDay;
The following code is what I am using
SELECT count(DISTINCT (
UserID)
) AS total, CONCAT(IF(date(LastModified) - INTERVAL 6 day < date(LastModified),
date(LastModified),
IF(WEEKDAY(date(LastModified) - INTERVAL 6 DAY) = 4,
date(LastModified) - INTERVAL 6 DAY,
date(LastModified) - INTERVAL ((WEEKDAY(date(LastModified)) - 4)) DAY)),
' - ', date(LastModified)) AS week
FROM `Purchase`
WHERE `OfferingID` =87
AND `Status`
IN ( 1, 4 )
GROUP BY week
The output I get is
total week
3 2013-01-30 - 2013-01-30
1 2013-01-31 - 2013-01-31
I'm not sure exactly how you want to display your week, the sql above is attempting to display date ranges. If this isn't a requirement, your query could be very simple, you can just offset your time by two days (since friday is two days away from the natural star of the week) and use the week function to get the week number.
The query would look like this:
select count(distinct (UserID)) as total
, year( LastModified + interval 2 day ) as year
, week( LastModified + interval 2 day ) as week_number
FROM `Purchase`
WHERE `OfferingID` =87
AND `Status`
IN ( 1, 4 )
group by year, week_number;