MySQL: Group by Austral year? - mysql

Let's say we have a simple table like so
DATE VALUE
--------------------
2013-01-01 23
2013-06-12 34
2013-07-22 788
2013-12-16 234
2014-01-23 56
2014-04-19 88
2014-09-23 7987
2014-11-05 66
2015-02-17 987
2015-05-05 896
Now let's suppose we want to extract the mean values grouped by year, we would use
SELECT AVG(`VALUE`) FROM tablename GROUP BY YEAR(`DATE`)
However, what if we define the year not from January to December, but rather from July to June (which makes quite a bit of sense for a lot of data if you're living in the Southern hemisphere).
I am sure there must be an easy way to achieve a July YEAR to June YEAR+1 grouping. It just seems to elude me.
-- EDIT --
Awesome! Two good solutions arrived within minutes of posting this question, that both deserved to be accepted. I accepted Roland's solution because of its brevity, but Leo Tara's reply made me aware that I forgot about outputting the associated austral year. So based on both answers I came up with this solution which does exactly what I was asking for:
SELECT
YEAR(`DATE` - INTERVAL 6 MONTH) as `australyear`,
AVG(`VALUE`)
FROM tablename
GROUP BY YEAR(`DATE` - INTERVAL 6 MONTH)

Just add 6 month to the date when grouping. I don't know the exact syntax in case of mysql, sorry.
Pseudocode:
SELECT AVG(`VALUE`) FROM tablename GROUP BY YEAR(`DATE` + '6 MONTHS');

Try this:
SELECT AVG(`VALUE`)
FROM tablename
GROUP BY
CASE
WHEN MONTH('DATE') BETWEEN 1 AND 6 THEN YEAR('DATE') - 1
ELSE YEAR(`DATE`)
END
If you want to show year on field list you must rewrite your query in this way:
SELECT
CASE
WHEN MONTH('DATE') BETWEEN 1 AND 6 THEN YEAR('DATE') - 1
ELSE YEAR(`DATE`)
END, AVG(`VALUE`)
FROM tablename
GROUP BY
CASE
WHEN MONTH('DATE') BETWEEN 1 AND 6 THEN YEAR('DATE') - 1
ELSE YEAR(`DATE`)
END
Test on Sql Fiddle

Related

MySQL, grouping by and performing a SUM within the groups

The table below contains records of shifts which have taken place. The start and end fields are the start and end timestamps of those shifts. I'm looking to build a query that will extract the total hours per month that the shifts cover.
Example table:
ID Start End
1 2018-10-23 10:30:00 2018-10-23 11:45:00
2 2018-10-22 22:00:00 2018-10-22 23:00:00
3 2018-11-22 22:00:00 2018-11-22 23:00:00
The ideal output would read:
Month Hours
10 2:15
11 1:00
I've got some of the elements worked out, using a SUM(timediff(end,start)) and GROUP BY, but havn't managed to get something good out!
Thanks!
Here you go:
select
month(start) as month,
time_format(sec_to_time(
sum(timestampdiff(second, start, end))
), '%H:%i') as hours,
sum(timestampdiff(second, start, end)) as seconds
from shift
group by month(start)
Result:
month hours seconds
----- ----- -------
10 02:15 8,100
11 01:00 3,600
Note: I added the extra column seconds in case you want to use this numeric value to do some extra processing.

SQL query to retrieve latest 2 week records

I have a database with CreatedDate is store in Unix epoch time and some other info. I want a query to able to retrieve latest 2 week record base on the last record.
Below is part of the example
ID User Ranking CreatedDate
-------------------------------------------------------
1 B.Sisko 1 1461136714
2 B.Sisko 2 1461123378
3 B.Sisko 3 1461123378
4 B.Sisko 3 1461600137
5 K.Janeway 4 1461602181
6 K.Janeway 4 1461603096
7 J.Picard 4 1461603096
The last record CreatedDate is 25 Apr 2016, so I want the record from 12 Apr to 25 Apr.
I not sure how to compare to get latest data? any suggestion
The simplest method is probably to just subtract two weeks from today's date/time:
where CreatedDate >= UNIX_TIMESTAMP() - 7*24*60*60
Another approach is to convert the value to a date/time:
where from_unixtime(CreatedDate) >= date_sub(now(), interval 2 week)
The advantage of this approach is that it is easier to align to days. So, if you want two weeks starting at midnight:
where from_unixtime(CreatedDate) >= date_sub(curdate(), interval 2 week)
The disadvantage is that the function on the column prevents the use of indices on that column.
EDIT:
This is definitely not how your question was phrased. But in that case, you should use:
select t.*
from t cross join
(select from_unixtime(max(CreatedDate)) as maxcd from t) m
where from_unixtime(CreatedDate) >= date_sub(maxcd, interval 2 week);
It may seem odd, but you need to execute two queries one to find the Maximum Date and knock off 14 days -- and then use that as a condition to requery the table. I used ID_NUM since ID is a reserved word in Oracle and likely other RDBMS as well.
SELECT ID_NUM, USER, RANKING,
TO_DATE('19700101000000', 'YYYYMMDDHH24MISS')+((CreatedDate-18000)
/(60*60*24)) GOOD_DATE
FROM MY_TABLE
WHERE
GOOD_DATE >=
(SELECT MAX( TO_DATE('19700101000000', 'YYYYMMDDHH24MISS')+
((CreatedDate-18000) /(60*60*24))) -14
FROM MY_TABLE)

MySQL Selecting Dates Within Number of Days

I have a MySQL table similar to this:
item | order | start date | end date
------------------------------------------
1 1 2015-09-15 2015-09-20
2 1 2015-09-15 2015-09-20
1 2 2015-09-20 2015-09-25
2 2 2015-09-20 2015-09-25
What I want to do is execute a query that will check if any end-dates are within 7 days of a future start date, and return the result. Does anyone know how this could be done?
EDIT: Should be more specific I suppose - the start date and end date of an order (say in this case order 2 from the example table) can be within 7 days of each other. I want to check if order 1's end date is within 7 days of order 2's start date. Sorry if that wasn't clear before.
You can use datediff function.
select * from table_name
where
start_date > curdate()
and datediff(end_date,start_date) between 0 and 7

Mysql query for group by month

I am looking to do something like get all rows from table
where date >='2012-05-05' and date<='2012-07-20'
I want MySQL to return "group by" rows mont wise incremented from
2012-05-05 to 2012-06-05(incerement 1 month)
2012-06-06 to 2012-07-06(increment 1` month)
and remaining 2012-07-07 to 2012-07-20 (group the remaining 14 days)
how can i write my query to achieve the same?
Thank you...
Try this solution:
You can GROUP BY the number of months elapsed from your parameter minimum (2012-05-05) + 1 to the date in each row via the TIMESTAMPDIFF() function:
GROUP BY TIMESTAMPDIFF(MONTH, '2012-05-05' + INTERVAL 1 DAY, date)
The reason why we +1 day to your minimum parameter is because:
2012-05-05 to 2012-06-04 is 0 months, but...
2012-05-05 to 2012-06-05 is 1 month
^ Because of that, the row(s) on 2012-06-05 would be grouped separately from dates that had 0 months elapsed when we actually want it grouped WITH them.
Edit: I was fiddling around with this solution not only grouping by the month intervals, but also displaying the from and to dates of each interval.
Check it out:
SQLFiddle Demo
You could use the case expression and then group by on the result of case.
SELECT
CASE
WHEN where date >='2012-05-05' and date<='2012-06-05' THEN 1
WHEN where date >='2012-06-06' and date<='2012-07-06' THEN 2
ELSE 3
END AS period, COUNT(*)
FROM your_table
GROUP BY period
Hope this help, I assumed the date range is dynamic like this :
2012-01-01 to 2012-02-01
2012-02-02 to 2012-03-02
2012-03-03 to 2012-04-03
2012-04-04 to 2012-05-04
2012-05-05 to 2012-06-05
...
So, I can group it using :
SELECT *, IF(day(date)>=month(date), month(date), month(date)-1) as PERIOD
FROM your_tablename
GROUP BY PERIOD;

SQL Server returns unexpected week number

I have some orders in a table and the last order date of 2011 is 20th Dec.
I'm using a sql command to calculate the number of orders in a given week:
SELECT CONVERT(VARCHAR(3),DATENAME(week,convert(datetime,order_date,103))) AS week,
COUNT(1) as orders
FROM order_table
where DATENAME(YEAR,convert(datetime,order_date,103)) = '2011'
GROUP BY CONVERT(VARCHAR(3),DATENAME(week,convert(datetime,order_date,103)))
order by week asc
It returns me the some of the following results:
Week | Orders
41 | 42
42 | 110
43 | 115
...
...
51 | 155
52 | 15
The trouble with this is is that the last order date of 2011 as mentioned that I have is 20th Dec 2011, which can't be week 52 so must be week 51.
I've got some other stats(off another system, not SQL server) which giving me some other figures and the last week on it is 51 which I have no doubt is correct. So there's going to be a queries if people are looking both!
Anyone have any idea or know how to sort this?
Thanks,
The iso_week of 20th Dec 2011 is 51. So maybe that is what you need.
SELECT datepart(iso_week, '2011-12-20')
SQL Counts a week as Sunday-Saturday, you can use the script below to see how the weeks break out for 2011. The 1st of January is a Saturday, which means the first week is only 1 day. There are 53 SQL weeks in 2011, and 53 weeks in most years
DECLARE #dStartDate DATETIME
SET #dStartDate = '01/01/2011'
WHILE #dStartDate < '01/01/2012'
BEGIN
PRINT CONVERT(VARCHAR, #dStartDate, 101)
+ ' : '
+ CONVERT(VARCHAR, DATEPART(WEEK, #dStartDate))
+ ' : '
+ DATENAME(DW, #dStartDate)
SET #dStartDate = #dStartDate + 1
END
If you want to change the day SQL counts as the first of the week, you can use the DATEFIRST command
http://msdn.microsoft.com/en-us/library/ms181598.aspx
SELECT DatePart(WEEK,order_date) AS WeekOfYear
FROM order_table
Should give you the week number.
So do
Select * from order_table Where DatePart(Week, order_date) = 52
See what is week 52 not what you think is 52.
PS Given you are starting week 1 on the 1/1 it's not possible to have a 52 week year, unless 1 and or 52 are not seven day weeks.