MySQL week numbers and New Year - mysql

The website I'm working on now has a dashboard showing data entered during the previous week by various users. I select this data using a simple WHERE clause:
SELECT * FROM table WHERE WEEK(date, 1) = WEEK(CURDATE(), 1) - 1
However, the New Year is coming soon, and when a user tries to view the dashboard on, for example, 3rd or 4th of January, my code is clearly going to give me a wrong result, because the last week's number of 2010 is 52. So, what would be the best way to alter my query to take into account the change of the year. And also, it would be cool to make it possible to select data entered 2, 3, 4,... weeks ago.

How about selecting the WEEK of the day seven days ago?
WHERE WEEK(date, 1) = WEEK(CURDATE() - INTERVAL 1 WEEK, 1)
This way you can select data entered 2,3,4 weeks ago:
WHERE WEEK(date, 1) = WEEK(CURDATE() - INTERVAL 2 WEEK, 1)

Why you can't use:
WHERE date between date_add(CurDate() - INTERVAL 1 WEEK) and CurDate()

Related

MYSQL WHERE clause, last week year over week

I have a portion of a WHERE clause below and I though I had this right but I dont seem to:
AND (WEEK(DeliveryDate, 1) = (WEEK(CURDATE(), 0) - 1))
AND (YEAR(DeliveryDate) = YEAR(CURDATE())))
The way I though this worked according to the documention was that the "1" here (WEEK(DeliveryDate, 1)' was telling it to start the week on Monday. Then the "0" here = (WEEK(CURDATE(), 0) - 1)) was telling it to start in the week that just ended. This is however not what is happening. Instead this expression is calculating the week the ended November 29th instead of this past week that ended December 6th. What is being missed?
EDIT 1
The above WHERE clause is what I was told to move to at one point at the suggestion of another user. I had previously been using CURDATE() then the Interval between X and Y to get one week ago, not including this week and not the last 7 days. Here is the result of the folling query:
select post_id,DeliveryDate from table where deliverydate >= now() - interval 1 week
If you are trying to see if DeliveryDate is in the previous week, where weeks start on Monday, do:
AND YEARWEEK(DeliveryDate, 1) = YEARWEEK(CURDATE() - INTERVAL 1 WEEK, 1)
Adjusting the return of week won't work well across year boundaries, and checking week and year separately can go wrong in a number of ways, and comparing week values using different modes isn't going to do anything useful.

select all data beginning from the first of the month sql

I'm trying to get data going back three months for monthly reports. I got to the point where i can get all the data. The problem is that it goes back 3 months based on the current date.
Example: If today is 7th of November it will give me the data up until the 7th of August.
I need it to give me the data going back three months but starting from the first of the month.
Example: today is the 7th of November, I'll need the data starting from the 1st of August.
Here is the code I'm using to get the data from three months back:
SELECT * FROM 'closed_wo_journal' WHERE date_time_stamp > CURDATE() - INTERVAL 3 MONTH
The date_trunc function is just what the doctor ordered:
SELECT *
FROM closed_wo_journal
WHERE date_time_stamp > DATE_TRUNC('MONTH', CURDATE() - INTERVAL '3 MONTH')
Here is logic to get the first of the month, three months ago:
SELECT j.*
FROM closed_wo_journal j
WHERE j.date_time_stamp >= ( CURDATE() - INTERVAL (1 - DAY(CURDATE()) DAY) ) - INTERVAL 3 MONTH )

SQL: Where between two dates without year?

I'm trying to query through historical data and I need to return data just from a 1 month period: 2 weeks back and 2 weeks forward,but I need the year to not matter.
So, if I was to make the query today I would want all rows with date between xxxx-06-31 and xxxx-07-27
Thanks in advance for the help!
EDIT:
I've tried two ways. both of which I believe will not work around the new year. One is to use datepart(day) and the other would be to simply take the year off of date and compare.
The best way to think of this problem is to convert your dates to a number between 0 and 365 corresponding to the day in the year. Then simply choosing dates where this difference is less than 14 gives you your two week window.
That will break down at the beginning or end of the year. But simple modular arithmetic gives you the answer.
Fortunately, MySQL has DAYOFYEAR(date), so it's not so complicated:
SELECT * FROM tbl t
WHERE
MOD(DAYOFYEAR(currdate) - DAYOFYEAR(t.the_date) + 365, 365) <= 14
OR MOD(DAYOFYEAR(t.the_date) - DAYOFYEAR(currdate) + 365, 365) <= 14
That extra + 365 is needed since MySQL's MOD will return negative numbers.
This answer doesn't account for leap years correctly. If the current year is not a leap year and the currdate is within 14 days of the end of the year, then you'll miss one day in Jan that you should have included. If you care about that, then you should replace 365 with [the number of days in the year - 1].
Supposed you have a date like this,
create table datelist
(
d date
);
insert into datelist values
('2012-07-01'),
('2011-06-29'),
('2012-07-02'),
('2010-07-05'),
('2012-05-31'),
('2010-06-30');
Try this query below,
SELECT d, date_format(d,'%Y-%b-%d')
FROM datelist
WHERE (MONTH(d) = 6 AND DAYOFMONTH(d) >= 30)
OR (MONTH(d) = 7 AND DAYOFMONTH(d) <= 27)
SQLFiddle Demo
Is it OK if the solution is terribly slow?
SELECT tbl.*
FROM tbl
INNER JOIN (SELECT COALESCE(DATE(CONCAT(yyyy, '-', MONTH(CURRENT_DATE), '-', DAYOFMONTH(CURRENT_DATE)),
DATE(CONCAT(yyyy, '-02-28'))) AS midpoint
FROM (SELECT DISTINCT(YEAR(d)) AS yyyy
FROM tbl) all_years) adjusted
ON tbl.datecol BETWEEN adjusted.midpoint - INTERVAL 2 WEEK
AND
adjusted.midpoint + INTERVAL 2 WEEK;
That computes all midpoints for all years in the data set, and then pulls records +- 2 weeks from any such midpoint, which handles end-of-year wrapping.
The COALESCE handles 02-29 on years without leapday (which MySQL will NULL-ify), forcing it down to 02-28.

Last n weekdays in sql where clausel

We are using MySQL as our database to store messages with timestamps. Is it possible to create a query that returns messages of the last n weekdays?
I.e. if n is 4 and today is Tuesday, I want messages from this weeks Monday, last weeks Friday, last weeks Thursday and last weeks Wednesday .
If you want to do this directly with mysql it would be a little complicated. As Vatev recommended you should calculate date star date in advance, but if you really want to do this, you'll probably need following functions:
ADD_DATE, with INTERVAL -N WEEKS
FLOOR, in C int/int would do just fine
MOD, a % b :)
WEEKDAY
First of all you need should count how many weeks you should go back, that's easy... For you one week = 5 days, that means
weeks = FLOOR(days / 5)
We've taken care of weeks, so we'll now have to work with the rest:
rest = days MOD 5
Now we have two cases, weekend has occurred or no, for the case that there wasn't weekend days are good. We have to add 2 days to skip it. The weekend occurred if (WEEKDAY(now) - rest) < 0
rest = IF( (WEEKDAY(now) - rest) < 0, rest + 2, rest)
And now we can build it to one par (let's assume you have {days} and {rest} pre-calculated):
WHERE date >= ADD_DATE(
ADD_DATE (
{now},
INTERVAL -IF( (WEEKDAY({now}) - {rest}) < 0, {rest} + 2, {rest}) DAYS,
),
INTERVAL -FLOOR({days} / 5) WEEKS
)
The best i can come up with is calculating the start date ({start_date} in the query) in the language of your choice and then running something like this:
SELECT some_things
FROM your_table
WHERE
WEEKDAY(time_column) < 5
AND time_column >= {start_date}
ORDER BY time_column DESC
You can also make a stored function to calculate 'the date x week days ago' and use it for {start_date}.
Have you tried something like this?
SELECT columns
FROM table
WHERE datediff(column_with_timestamp,NOW()) > n
Where N is as you defined above, the number of days you're looking for.
COL >= date_sub( NOW(), interval 1 week) and
weekday( COL ) < 5
date_sub is to seek rows created last week
weekday is to exclude sunday or saturday

How do I select two weeks ago in MYSQL?

I have a report that is driven by a sql query that looks like this:
SELECT batch_log.userid,
batches.operation_id,
SUM(TIME_TO_SEC(ramses.batch_log.time_elapsed)),
SUM(ramses.tasks.estimated_nonrecurring + ramses.tasks.estimated_recurring),
DATE(start_time)
FROM batch_log
JOIN batches ON batch_log.batch_id=batches.id
JOIN ramses.tasks ON ramses.batch_log.batch_id=ramses.tasks.batch_id
JOIN protocase.tblusers on ramses.batch_log.userid = protocase.tblusers.userid
WHERE DATE(ramses.batch_log.start_time) > "2011-02-01"
AND ramses.batch_log.time_elapsed > "00:03:00"
AND DATE(ramses.batch_log.start_time) < now()
AND protocase.tblusers.active = 1
AND protocase.tblusers.userid NOT in ("ksnow","smanning", "dstapleton")
GROUP BY userid, batches.operation_id, date(start_time)
ORDER BY start_time, userid ASC
Since this is to be compared with the time from the current payperiod it causes an error.
Our pay periods start on a Sunday, the first pay period was 2011-02-01 and our last pay period started the 4th of this month. How do I put that into my where statement to strip the most recent pay period out of the query?
EDIT: So now I'm using date_sub(now(), INTERVAL 2 WEEK) but I really need a particular day of the week(SUNDAY) since it is wednesday it's chopping it off at wednesday.
You want to use DATE_SUB, and as an example.
Specifically:
select DATE_SUB(curdate(), INTERVAL 2 WEEK)
gets you two weeks ago. Insert the DATE_SUB ... part into your sql and you're good to go.
Edit per your comment:
Check out DAYOFWEEK:
and you can do something along the lines of:
DATE_SUB(DATE_SUB(curdate(), INTERVAL 2 WEEK), INTERVAL 2 + DAYOFWEEK(curdate()) DAY)
(I don't have a MySql instance to test it on .. but essentially subtract the number of days after Monday.)
Question isn't quite clear, especially after the edit - it isn't clear now is the "pay period" two weeks long or do you want just last two weeks back from last sunday? I assume that the period is two weeks... then you first need to know how many days the latest period (which you want to ignore, as it isn't over yet) has been going on. To get that number of days you can use expression like
DATEDIFF(today, FirstPeriod) % 14
where FirstPeriod is 2011-02-01. And now you strip that number of days from the current date in the query using date_sub(). The exact expression depends on how the period is defined but you should get the idea...