SQL View to show interval of 12 months and by year - mysql

Right now one of the other programmers wrote this view to show interval of 6months. How do i write this so that it shows interval of 12 months grouped by month but only for year 2011
I'd like to copy it for a separate view of 12 months grouped by month but only for year 2012
CREATE ALGORITHM=UNDEFINED DEFINER=`root`#`%`
SQL SECURITY DEFINER VIEW `vw_dash_bymonth`AS
select
month(from_unixtime(`tbl_services`.`datetime`)) AS` month1`,
date_format(from_unixtime(`tbl_services`.`datetime`),'%Y') AS` year1`,
date_format(from_unixtime(`tbl_services`.`datetime`),'%d') AS `day1`,
`tbl_services`.`datetime` AS `realdate`,sum(`tbl_services`.`gallons`) AS `gallons`,
count(0) AS `service`,
round(avg(`tbl_services`.`gallons`),1) AS `average`
from `tbl_services`
where (from_unixtime(`tbl_services`.`datetime`) > (now() - interval 6 month))
group by month(from_unixtime(`tbl_services`.`datetime`))

If you look at the where clause
where (from_unixtime(`tbl_services`.`datetime`) > (now() - interval 6 month))
I believe this is getting the dates from everything from 6 months ago until today. If you want 12 months in 2011 I think you could replace that line with something like:
where (from_unixtime(`tbl_services`.`datetime`) >= DATE('2011-01-01 00:00:00'))
AND (from_unixtime(`tbl_services`.`datetime`) < DATE('2012-01-01 00:00:00'))
Although I don't know MySQL (just SQLServer) so if this doesn't work, hopefully someone else can tell me where I went wrong.
It can be simplified to:
where (from_unixtime(`tbl_services`.`datetime`) >= '2011-01-01')
AND (from_unixtime(`tbl_services`.`datetime`) < '2012-01-01')

SELECT DISTINCT FROM_UNIXTIME('date','%m-%Y') AS month,
COUNT(`id`) AS count
FROM 'blog'
GROUP BY month
ORDER BY month DESC LIMIT 0,12

SELECT
MONTH( UNIX_TIMESTAMP( t.`datetime`) ) AS month1,
DATE_FORMAT( UNIX_TIMESTAMP( t.`datetime`), '%Y' ) AS year1,
DATE_FORMAT( UNIX_TIMESTAMP( t.`datetime`), '%d') AS day1,
t.`datetime` AS realdate,
SUM(t.gallons) AS gallons,
COUNT(*) AS `service`,
ROUND( AVG( t.gallons ), 1 ) AS `average`
FROM
tbl_services AS t
CROSS JOIN
( SELECT 2011 AS YearToCheck
) AS c
WHERE t.`datetime` >= UNIX_TIMESTAMP( MAKEDATE( YearToCheck, 1 ) )
AND t.`datetime` < UNIX_TIMESTAMP( MAKEDATE( YearToCheck+1, 1 ) )
GROUP BY MONTH( FROM_UNIXTIME( t.`datetime` ) )

Related

Should I Write Lengthy SQL Query or Breakdown into Few Iterations

I have a very lengthy SQL query to fetch the expected output but on the other side, I also can generate the expected output by using multiple iterations.
Which one should I use?
I care about performance and writing better code.
By using length SQL query it takes around 3000ms to generate the output
Need about 4 ~ 5 iterations to generate the output
What is the query/code is doing
This code is generating the total number of the forecast record based on the financial year regardless the total number is 0 or not.
Using Length SQL Query
SELECT
CONCAT('FY\'', SUBSTR(`quarters`.fy, 3), ' Q', `quarters`.fy_quarter) AS name,
(
SELECT
COUNT(*)
FROM
member_project_stages
WHERE
YEAR ( member_project_stages.start_at ) = `quarters`.fy
AND QUARTER ( member_project_stages.start_at ) = `quarters`.fy_quarter
AND member_project_stages.stage_id = 9
) AS actual,
(
SELECT
COUNT(*)
FROM
projects AS a
WHERE
( a.forecast IS NOT NULL AND a.forecast > '' )
AND a.forecast LIKE CONCAT( '%FY\'', SUBSTR( `quarters`.fy, 3 ), '%' )
AND a.forecast LIKE CONCAT( '% Q', `quarters`.fy_quarter, '%' )
AND a.deleted_at IS NULL
GROUP BY
a.forecast
) AS forecast
FROM
`member_project_stages`,
(
SELECT YEAR
(
DATE_ADD( CURDATE(), INTERVAL - 9 MONTH )) AS fy,
QUARTER (
DATE_ADD( CURDATE(), INTERVAL - 9 MONTH )) AS fy_quarter UNION
SELECT YEAR
(
DATE_ADD( CURDATE(), INTERVAL - 6 MONTH )) AS fy,
QUARTER (
DATE_ADD( CURDATE(), INTERVAL - 6 MONTH )) AS fy_quarter UNION
SELECT YEAR
(
DATE_ADD( CURDATE(), INTERVAL - 3 MONTH )) AS fy,
QUARTER (
DATE_ADD( CURDATE(), INTERVAL - 3 MONTH )) AS fy_quarter UNION
SELECT YEAR
(
CURDATE()) AS fy,
QUARTER (
CURDATE()) AS fy_quarter UNION
SELECT YEAR
(
DATE_ADD( CURDATE(), INTERVAL 3 MONTH )) AS fy,
QUARTER (
DATE_ADD( CURDATE(), INTERVAL 3 MONTH )) AS fy_quarter UNION
SELECT YEAR
(
DATE_ADD( CURDATE(), INTERVAL 6 MONTH )) AS fy,
QUARTER (
DATE_ADD( CURDATE(), INTERVAL 6 MONTH )) AS fy_quarter UNION
SELECT YEAR
(
DATE_ADD( CURDATE(), INTERVAL 9 MONTH )) AS fy,
QUARTER (
DATE_ADD( CURDATE(), INTERVAL 9 MONTH )) AS fy_quarter
) AS `quarters`
GROUP BY
`quarters`.fy,
`quarters`.fy_quarter"
Using Iteration
for(...) {
run SQL query
}
for(...) {
using the previous output and run SQL query again
}
for(...) {
using the previous output and run SQL query again
}
for(...) {
using the previous output and run SQL query again
}
Finally I have my output
Its true that interacting with DB is costlier. Hence people prefer combining several queries into 1 query to optimize the performance.
And for better code, why not explain the logic in comments.

MYSQL Birthday Query

So im having troubles with my query, Its select the next three birthdays but say if some one birthday is on the April 12th. As soon as April 1st come along that birthday is no longer displayed.
SELECT `users`.`name`,
Date_format(`users_detail`.`dob_date`, '%d') AS day,
Date_format(`users_detail`.`dob_date`, '%M') AS month
FROM `users_detail`
JOIN `users`
ON `users`.`id` = `users_detail`.`id`
WHERE Date_add(`users_detail`.`dob_date`,
INTERVAL Year( Curdate() )- Year(`users_detail`.`dob_date`) + IF(
Dayofyear(
Curdate() ) >= Dayofyear(`users_detail`.`dob_date`), 1, 0 ) year)
BETWEEN Curdate() AND Date_add(Curdate(), INTERVAL 11 month)
ORDER BY `users_detail`.`dob_date` ASC
LIMIT 3
Can you try this ?
SELECT `users`.`name`
FROM `users_detail`
WHERE DATE_ADD(`users_detail`.`dob_date`,
INTERVAL YEAR(CURDATE())-YEAR(`users_detail`.`dob_date`)
+ IF(DAYOFYEAR(CURDATE()) > DAYOFYEAR(`users_detail`.`dob_date`),1,0)
YEAR)
BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 11 month)
ORDER BY `users_detail`.`dob_date` ASC
LIMIT 3

Why am i getting this error message ( #1111 - Invalid use of group function )?

I am trying to retrieve the TIMEDIFF from the last_call field of every row, where TIMEDIFF between current row and next row is greather than 10 min!
Can someone please help? Meybe there is a better way of doing this?
My goal is to get the total of all timediff between severall database entrys but only if they are greather than 10 min.
SELECT DATE_FORMAT( last_call, '%d' ) AS 'day',
(
SELECT TIME_TO_SEC(TIMEDIFF(MAX(cl1.last_call), MIN(cl1.last_call)))
FROM calls AS cl1
WHERE TIME_TO_SEC(TIMEDIFF(MAX(cl1.last_call), MIN(cl1.last_call))) > 600
AND cl1.calling_agent=9
AND EXTRACT(DAY FROM cl1.last_call ) = EXTRACT(DAY FROM calls.last_call )
) AS 'brake'
FROM calls
WHERE calling_agent =9
AND last_call > DATE_SUB( now( ) , INTERVAL 12 MONTH )
GROUP BY EXTRACT( DAY FROM last_call )

How to select 6 months of data in MySQL, grouped between the 22nd and 21st of the next month

I have a table that contains the amount of data used each day, it looks something like this:
date | bytes
------------------
2014-01-1 | 12345
2014-01-2 | 56789
2014-01-3 | 78901
...
2014-02-1 | 12345
2014-02-2 | 56789
2014-02-3 | 78901
...
What I need to do is get the last 6 monthly totals, however the month must start on the 22nd day of the month and finish on the 21st day of the following month. For the current month it should start on the 22nd and finish today.
The best I can come up with is the following, the problem is - it is very messy and doesn't seem to give the correct result.
SELECT monthname(`date`),sum(`bytes`)
FROM `trafficDaily`
WHERE `date` between STR_TO_DATE( CONCAT( "22,", MONTH( NOW( ) )-6 , ",", YEAR( NOW( ) ) ) , "%d,%m,%Y" )
and STR_TO_DATE( CONCAT( "21,", MONTH( NOW( ) ) , ",", YEAR( NOW( ) ) ) , "%d,%m,%Y" )
group by month(DATE_SUB(`date`, INTERVAL 21 DAY))
order by `date`
Thank you in advance for your help.
You can do so by using user-defined variables to track the the change of month i.e in your case month starts from 21st
SELECT
MONTHNAME(STR_TO_DATE(group_day, '%m')) month_name ,
SUM(`bytes`) `sum`
FROM (
SELECT *,
#changemonth:= CASE
WHEN DAY(`date`) > 21
THEN #month
WHEN MONTH(`date`) <> #month
THEN #month
ELSE #month - 1
END group_day,
#month:= MONTH(`date`)
FROM
t ,(SELECT #changemonth:=0,
#month:= (SELECT MONTH(`date`) FROM t
WHERE `date` > NOW() - INTERVAL 6 MONTH ORDER BY `date` LIMIT 1) aa
) tt
WHERE `date` > NOW() - INTERVAL 6 MONTH
ORDER BY `date`
) a
GROUP BY group_day
Demo for last 3 months
Edit from comments for the case when January lies in last 6 month period
SELECT
MONTHNAME(
STR_TO_DATE(
CASE WHEN group_day < 1
THEN 12 ELSE group_day
END, '%m'
)
) month_name ,
SUM(`bytes`) `sum`
FROM (
SELECT *,
#changemonth:= CASE
WHEN DAY(`date`) > 21
THEN #month
WHEN MONTH(`date`) <> #month
THEN #month
ELSE #month - 1
END group_day,
#month:= MONTH(`date`)
FROM
t ,(SELECT #changemonth:=0,
#month:= (SELECT MONTH(`date`) FROM t
WHERE `date` > NOW() - INTERVAL 6 MONTH ORDER BY `date` LIMIT 1) aa
) tt
WHERE `date` > NOW() - INTERVAL 6 MONTH
ORDER BY `date`
) a
GROUP BY group_day
Demo with January
You have at least two options:
1st option
Create a calendar table and assign the 'business month' to each days. You can prepare your table for a long time period, then you can join to that table by date and you can do the grouping. If you have to do this calculation regularry, this is a good solution. (You can upgrade and use the calendar table to do several tasks)
2nd option
You can calculate the 'business month' by the date using the following query. (Please note, that I did not tested this query, so there could be typos).
SELECT
CASE
WHEN DAY(date) >= 22 THEN CONCAT(YEAR(date), '-', MONTH(date))
ELSE CONCAT(YEAR(date - INTERVAL 1 MONTH), '-', MONTH(date - INTERVAL 1 MONTH))
END AS m,
SUM(bytes)
FROM
log -- Use your table name instead :)
GROUP BY
CASE
WHEN DAY(date) >= 22 THEN CONCAT(YEAR(date), '-', MONTH(date))
ELSE CONCAT(YEAR(date - INTERVAL 1 MONTH), '-', MONTH(date - INTERVAL 1 MONTH))
END
You can adjust the calculation to your needs.

Retrieve data for specific months

MySQL Query is like this
SELECT MONTHNAME(access_date) as date,
DATE_FORMAT( access_date, '%m/%Y' ) as month_date ,
COUNT( log_id ) as total_count
FROM user_activity_log
WHERE dam_id = (
SELECT dam_id
FROM dam_content_details
WHERE content_type= '$content_type'
)
AND access_date >= last_day(NOW() - INTERVAL ($month) MONTH)
GROUP BY MONTH( access_date )
ORDER BY access_date ASC
i will pass the numbers like 1,2,3.... then its giving value for that month.
The problem i faced is it retrieving the data per 30 days,60 days like that. I want if i will write $month = '1; then it should return the current month data & previous month data starting from day 1.
My sample output - $month = 2
date month_date total_count
--------- ------------ -----------
December 12/2013 4
January 01/2014 1
I want for december it should calculate from 12/01/2013. 1st December 2013. Any idea how to solve it ?
You just have to remove = from >=.
Try this:
SELECT MONTHNAME(access_date) as date,
DATE_FORMAT( access_date, '%m/%Y' ) as month_date ,
COUNT( log_id ) as total_count
FROM user_activity_log
WHERE dam_id = (SELECT dam_id FROM dam_content_details WHERE content_type= '$content_type') AND
access_date > LAST_DAY(NOW() - INTERVAL (($month)+1) MONTH)
GROUP BY MONTH( access_date )
ORDER BY access_date ASC