SELECT DATE(STR_TO_DATE(CONCAT(CONCAT(YEAR('$uDate1'), week), ' Monday'), '%X%V %W') +
INTERVAL (7 - DAYOFWEEK(STR_TO_DATE(CONCAT(CONCAT(YEAR('$uDate1'), week), ' Monday'),
'%X%V %W'))) DAY)
as week_end_date
What this statement does is take the date I give it ($uDate1) and give me the week end date (Saturday) of that week. This works well and I am happy with it, kinda.
I was wondering if there were some things I missed that would either make this more efficient or even if I missed some shortcuts to this.
Any suggestions for me?
week >= WEEK('$uDate1') AND week <= WEEK('$uDate2')
This is in my WHERE clause. So basically if I use this...
DATE('$uDate1', INTERVAL 7 - DAYOFWEEK('$uDate1') DAY)
...then it returns the same day for all records. I need it to be able to go over a span of a few weeks.
I have a column in my database named 'week'. It simply stores an INT that corresponds to the week of the year. (ex. 21 for this week)
I then have two date picker boxes. The output gets the week end date based of each week that is BETWEEN and INCLUDES the days chosen.
5/10/2016 & 5/26/2016 outputs 5/14/2016, 5/21/2016, 5/28/2016
What gets exported to CSV file looks something like this..
WEEK END, LAST NAME, FIRST NAME, ...
5/10/2016, Smith, John, ...
5/26/2016, Jones, James, ...
It outputs anyone who had hours during the week, with the week end date.
SIDE NOTE: I do appreciate the comments and help. I don't want anyone to stress over this though! Just curious if better way. :)
I am not sure why your current SQL is so complicated.
You say it is just to take a date and give me the week end date (Saturday) of that week .
How you are doing this at the moment is:-
Yours is taking the year
Adding the week of the year (I assume - should be WEEK('$uDate1') I think)
Adding on the day as a string (so for example for today it would be 2016 21 Monday )
Changing that string back to a date a datetime value
Converting that datetime value back to a date.
Then taking the year again
Adding the week of the year again
Getting the day of the week of the resulting string. As you have concatenated Monday on to the date then the day of the week will always be 2.
Taking that resulting day of the week and subtracting it from 7. As the day of the week will always be 2 this will always result in 5
Adding on the day as a string (so for example for today it would be 2016 21 Monday ).
This value is then added on to the previously calculated date, taking the Monday date and adding 5 days.
My suggestion was to just use:-
DATE_ADD($uDate1, INTERVAL 7 - DAYOFWEEK($uDate1) DAY)
which is far simpler, and appears to cover your requirements.
EDIT
Looking at your edit you want a list of all the Saturdays for weeks all or partially between 2 passed dates.
If so I think the following will do it and hopefully be more efficient as there is no need to translate dates to and from string. Note it relies on your week table to add to the date, hence only copes with date ranges of up to that many weeks.
SELECT DATE_ADD(DATE_ADD('$uDate1', INTERVAL 7 - DAYOFWEEK('$uDate1') DAY), INTERVAL `week` WEEK) AS aDate
FROM `week`
HAVING aDate BETWEEN '$uDate1' AND DATE_ADD('$uDate2', INTERVAL 7 - DAYOFWEEK('$uDate2') DAY)
ORDER BY aDate
As I mentioned in comment you should move this transformation from mysql query to php code.
I see no reason to do this calculation on mysql side.
http://ideone.com/48zLvF
$week_day = intval(date('w',$uDate1));
if ($week_day<6) {
$end_of_week = $uDate1+(86400*(6-$week_day));
} else {
$end_of_week = $uDate1;
}
Related
I am trying to get data by week, month and year.
I store date YYYY-MM-DD HH:MM:SS.
What I am doing is below;
Fetch one week old data;
query + AND WEEK(date) = WEEK(CURDATE())
Fetch a month old data;
query + AND MONTH(date) = MONTH(CURDATE())
The thing is I couldnt be able to get the data correct. For instance when I want to get week old data, I am gettin a year old one too.
Is there any other query that I could use? I have tried DATE(NOW()) - INTERVAL 30 DAY. It works but very slow.
Thanks!
I believe that the problem is that the WEEK function returns the week of the year. So, Jan 1st 2017 might be week 1 (also might be week 53 of the previous year depending on the day of the week and how MySQL handles it). But then, Jan 1st of 2016 is also week 1 - just for a different year.
Trying changing it to:
query + AND WEEK(date) = WEEK(CURDATE()) AND YEAR(date) = YEAR(CURDATE())
Also, if you're storing this as a string then definitely change it to a DATETIME
WHERE ...
AND date >= CURDATE() - INTERVAL 7 DAY
AND date < CURDATE()
Gives you the 7 days ending with yesterday. Use other techniques to get a particular month or week.
This technique is also much faster for large tables with a suitable index. Hiding date inside a function, such as WEEK() prevents the use of an index.
I need some help with running a query at month end. Each 1st working day of a month may differ, and therefore I may only be at work on the 3rd of a given month.
I am trying to figure out what my WHERE statement would look like to select data for the current month, unless it is:
1st of a month, then it will need to select everything from the previous month
1st working day of a month, which could be the 3rd. It will then also need to select the previous month's data.
These are two scenarios I am currently playing with, and don't have data to test it with as yet.
I have thought about doing
WHERE
MONTH(action_date) = MONTH(DATE_SUB(CURDATE(),INTERVAL 1 DAY))
But this then also returns data from 2016.
I have also thought of doing
WHERE
action_date = DATE_SUB(CURDATE(),INTERVAL 1 DAY)
But this would not work if today was say Monday the 3rd.
I would appreciate any answers that would give me the best way of doing this
You could simply subtract a few more days or even a month from the date, as all you will actually get from the subtraction is a month anyway
MONTH(DATE_SUB(CURDATE(),INTERVAL 5 DAY))
OR
MONTH(DATE_SUB(CURDATE(),INTERVAL 1 MONTH))
I have the following tables:
In other words I have a set of customers I follow throughout time. I have a column of the date of their first purchase, and another column with another purchase they made at another time.
I want to make a column which specifies the time period in which the specific purchase was made. The time periods should be defined such that a new period starts the 20th each month and the first period for each customer should therefore be the day they made their first purchase and until the 20th.
This is illustrated below:
What I need:
I have tried to implement this via a handful of if statements like:
WHEN DAY(c.created)<21 and DAY(s.created)<21 and year(c.created)-year(s.created)=0
THEN MONTH(c.created)-MONTH(s.created)+1
WHEN DAY(c.created)>20 and DAY(s.created)<21 and year(c.created)-year(s.created)=0
THEN MONTH(c.created)-MONTH(s.created)+2
and so on.
I want to know if there is an easy(er) and simple(r) way to handle this problem?
I work in MySQL Workbench 6.3 CE
The date of the first day of the calendar month in which a customer made a purchase can be found like this:
DATE_FORMAT(First_purchase , '%Y-%m-01')
So, the date of the first day of your fiscal month, which starts on the 20th of each calendar month, can be found like this.
DATE_FORMAT(First_purchase - INTERVAL 19 DAY, '%Y-%m-01') + INTERVAL 19 DAY
Then, you can use TIMESTAMPDIFF as follows to get the number of months between two of these sorts of numbers.
TIMESTAMPDIFF(
MONTH,
DATE_FORMAT(First_purchase - INTERVAL 19 DAY, '%Y-%m-01') + INTERVAL 19 DAY,
DATE_FORMAT(Date_created - INTERVAL 19 DAY, '%Y-%m-01') + INTERVAL 19 DAY) + 1
That will get you the number of the fiscal month, starting with First_purchase, in which Date_created is found, where the first fiscal month has the number 1.
Using native date arithmetic in place of DAY(), MONTH(), and YEAR() functions is much more likely to keep working over ends of years and in leap years and all that.
I currently have a query that is getting the records where their deadline is less than 3 months away. The deadline is stored as a Date, but the year is not important as this record should flag up every year.
My query:
SELECT client_name
FROM client
WHERE MOD(DAYOFYEAR(deadline) - DAYOFYEAR(CURDATE()), +365) <= 90
AND DAYOFYEAR(deadline) > DAYOFYEAR(CURDATE())
Apologies if there’s errors in the syntax as I’m writing this from memory – but it does work.
It works up until a deadline is in the first quarter and the current date is in the final quarter then it no longer returns the record. How do I get around this?
So the query needs to return the records that have a deadline within 3 months of the current date. The Year in the deadline date should be ignored as this could be years ago, but it is the day and month of the deadline that is important.
Or is the problem the date I am storing? Should I update this each year?
Thanks
One approach is to use a conditional test like this:
WHERE CONCAT(YEAR(NOW()),DATE_FORMAT(d.deadline,'-%m-%d'))
+ INTERVAL CONCAT(YEAR(NOW()),DATE_FORMAT(d.deadline,'-%m-%d'))<NOW() YEAR
< NOW() + INTERVAL 3 MONTH
We can unpack that a little bit. On that first line, we're creating a "next due" deadline date, by taking the current year, and appending the month and day value from the deadline.
But there's a problem. Some of those "next due" deadline dates are in the past. So, to handle that problem (when the 3 month period "wraps" into the next year), we need to add a year to any "next due" deadline date that's before the current date.
Now, we can compare that to a date 3 months from now, to determine if the "next due" deadline date is in the next 3 months.
That's a bit complicated.
Here's a SQL Fiddle as a demonstration: http://sqlfiddle.com/#!2/c90e9/3.
For testing, NOW() is inconvenient because it always returns today's date. So, for testing, we replace all occurrences of NOW() with a user-defined variable #now, and set that to various dates, so we can appropriately test.
Here's the SQL statement I used for testing. The first expression is the conditional test we're planning on using in the WHERE clause. For testing, we want to return all the rows, and just see which rows get due_in_3mo flagged as TRUE (1) and which get flagged as FALSE (0).
The second expression in the SELECT list just the "next due" deadline date, same as used in the first expression.
The rest of the expressions are pretty self-explanatory... we also want to display the date 3 months in the future we're comparing to, and the original "deadline" date value.
SELECT
CONCAT(YEAR(#now),DATE_FORMAT(d.deadline,'-%m-%d'))
+ INTERVAL CONCAT(YEAR(#now),DATE_FORMAT(d.deadline,'-%m-%d'))<#now YEAR
< #now + INTERVAL 3 MONTH
AS `due_in_3mo`
, CONCAT(YEAR(#now),DATE_FORMAT(d.deadline,'-%m-%d'))
+ INTERVAL CONCAT(YEAR(#now),DATE_FORMAT(d.deadline,'-%m-%d'))<#now YEAR
AS `next_due`
, d.id
, d.deadline + INTERVAL 0 DAY AS `deadline`
, #now + INTERVAL 3 MONTH AS `now+3mo`
, #now + INTERVAL 0 DAY AS `now`
FROM d d
CROSS
JOIN (SELECT #now := '2015-11-01') i
ORDER BY d.id
Change the value assigned to #now in the inline view (aliased as i) to test with other date values.
(You may want to use DATE(NOW()) in place of NOW() so that times don't get mixed in, and you may want to subtract another day from that, that really just depends how you want to handle the edge case of a deadline with month and day the same as the current date. (i.e. do you want to handle that as "in the past" or not.)
To summarize the approach: generate the "next due" deadline date as a DATE value in the future, and compare to the a date 3 months from now.
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...