how i can get these with mysql? - mysql

I am new to mysql.
I have on survey with clicks, period(date). Now i have to find out number of clicks per month, like:
MON CLICKS
nov 0
oct 34
sep 67
aug 89
I have used code like this:
select MONTHNAME(period) mon, IFNULL(count(id),0) as Clicks
from survey
where period > DATE_SUB(now(), INTERVAL 3 MONTH)
group by EXTRACT(MONTH FROM period)
It is not working for with no records.
Here one thing I suppose there is no record in that month it should show 0: if there is no record in nov the number of clicks should be 0.
my table structure was like this
CREATE TABLE `survey` (
`id` int(2) NOT NULL auto_increment,
`period` datetime default NULL)
for last four weeks i have used
SELECT uq.timespan, COALESCE(tsq.TotalClicks, 0) as Clicks FROM (
SELECT '22-28 days' as timespan
union SELECT '15-21 days'
union SELECT '8-14 days'
union SELECT 'up to 7 days'
)uq LEFT JOIN (
SELECT CASE
WHEN submitdate >= NOW() - INTERVAL 4 WEEK
AND submitdate < NOW() - INTERVAL 3 WEEK THEN '22-28 days'
WHEN submitdate >= NOW() - INTERVAL 3 WEEK
AND submitdate < NOW() - INTERVAL 2 WEEK THEN '15-21 days'
WHEN submitdate >= NOW() - INTERVAL 2 WEEK
AND submitdate < NOW() - INTERVAL 1 WEEK THEN '8-14 days'
WHEN submitdate >= NOW() - INTERVAL 1 WEEK THEN 'up to 7 days'
END Weeksubmitdate,
count(id) TotalClicks
FROM survey
WHERE submitdate >= NOW() - INTERVAL 4 WEEK
GROUP BY Weeksubmitdate
)tsq ON uq.timespan = tsq.Weeksubmitdate
Any help?

I usually do Pivot table to achieve this. Assuming your click information is stored into a table named SURVEY and assuming only the date/time of the click is stored into one column of the SURVEY table (which is all what you need) then here is one way to do it:
select year(period),
sum(case when month(period)=1 then 1 else 0 end) jan,
sum(case when month(period)=2 then 1 else 0 end) feb,
sum(case when month(period)=3 then 1 else 0 end) mar,
sum(case when month(period)=4 then 1 else 0 end) apr,
sum(case when month(period)=5 then 1 else 0 end) may,
sum(case when month(period)=6 then 1 else 0 end) jun,
sum(case when month(period)=7 then 1 else 0 end) jul,
sum(case when month(period)=8 then 1 else 0 end) aug,
sum(case when month(period)=9 then 1 else 0 end) sep,
sum(case when month(period)=10 then 1 else 0 end) oct,
sum(case when month(period)=11 then 1 else 0 end) nov,
sum(case when month(period)=11 then 1 else 0 end) dec
from survey
group by year(period)
The output is something like:
---------------------------------------------------------------------------------
| Year | JAN | FEB | MAR | APR | MAY | JUN | JUL | AUG | SEP | OCT | NOV | DEC |
---------------------------------------------------------------------------------
| 2012 | 5 | 20 | 13 | 0 | 0 | 65 | 15 | 0 | 0 | 21 | 0 | 0 |
---------------------------------------------------------------------------------
I even set up the same Fiddle SQL for you
SQL Fiddle Demo
An alternative way (Column based for the last 4 months even with ZERO count):
SQL Fiddle Demo
SELECT mon,
sum(clicks) clicks
FROM ( SELECT month(period) mnth,
date_format(period,'%b') mon,
count(1) clicks
FROM survey
WHERE month(period) BETWEEN month(curdate()) - 4 AND month(curdate())
GROUP BY 1, 2
UNION ALL
SELECT 1 mnth, 'Jan' mon, 0 clicks
UNION ALL
SELECT 2 mnth, 'Feb' mon, 0 clicks
UNION ALL
SELECT 3 mnth, 'Mar' mon, 0 clicks
UNION ALL
SELECT 4 mnth, 'Apr' mon, 0 clicks
UNION ALL
SELECT 5 mnth, 'May' mon, 0 clicks
UNION ALL
SELECT 6 mnth, 'Jun' mon, 0 clicks
UNION ALL
SELECT 7 mnth, 'Jul' mon, 0 clicks
UNION ALL
SELECT 8 mnth, 'Aug' mon, 0 clicks
UNION ALL
SELECT 9 mnth, 'Sep' mon, 0 clicks
UNION ALL
SELECT 10 mnth, 'Oct' mon, 0 clicks
UNION ALL
SELECT 11 mnth, 'Nov' mon, 0 clicks
UNION ALL
SELECT 12 mnth, 'Dec' mon, 0 clicks) a
WHERE mnth BETWEEN month(curdate()) - 4 AND month(curdate())
GROUP BY 1
ORDER BY mnth

You need to join to a table that contains all month names. Here's one way to do it:
select
mon,
ifnull(count(id), 0) as Clicks
from (select 'nov' as mon union select 'oct' union select 'sep' union select 'aug') m
left join survey on MONTHNAME(period) = mon
where submitdate > DATE_SUB(now(), INTERVAL 3 MONTH)
group by 1

select MONTHNAME(STR_TO_DATE(month(period), '%m'))as 'month',count(*) as clicks
from survey group by month(period)

Related

Transpose row to columns in SQL/PHP

I fetched the following data:
MONTH | TOTAL
-------------------------
Jan | 100
Feb | 200
Mar | 300
Using this query:
$query = "SELECT DATE_FORMAT(date,'%b') AS MONTH, SUM(col1+col2) AS TOTAL FROM myTable GROUP BY YEAR(date),MONTH(date)";
How can I edit the above query or re-write to get the following result:
JAN | FEB | MAR
-------------------------
100 | 200 | 300
I have gone through almost all the the other similar posts. However, sql transposing, to me, is very confusing. Any input is much appreciated!
You can use conditional aggregation. The following will work in either SQL Server or MySQL:
select year(date),
sum(case when month(date) = 1 then col1 + col2 else 0 end) as jan,
sum(case when month(date) = 2 then col1 + col2 else 0 end) as feb,
sum(case when month(date) = 3 then col1 + col2 else 0 end) as mar
from mytable
group by year(date)
order by year(date);
EDIT (regarding the comment):
select year(date),
sum(case when month(date) = 1 then val else 0 end) as jan,
sum(case when month(date) = 2 then val else 0 end) as feb,
sum(case when month(date) = 3 then val else 0 end) as mar
from (select t.*, (col1 + col2) as val
from mytable
) t
group by year(date)
order by year(date);

MySQL monthly Sale of last 12 months including months with no Sale

SELECT DATE_FORMAT(date, "%b") AS month, SUM(total_price) as total
FROM cart
WHERE date <= NOW()
and date >= Date_add(Now(),interval - 12 month)
GROUP BY DATE_FORMAT(date, "%m-%Y")
This query displaying result for only existing month. I need all 12 months sales.
Output:
"month" "total"
--------------
"Jun" "22"
"Aug" "30"
"Oct" "19"
"Nov" "123"
"Dec" "410"
Required Output:
"month" "total"
--------------
"Jan" "0"
"Feb" "0"
"Mar" "0"
"Apr" "0"
"May" "0"
"Jun" "22"
"Jul" "0"
"Aug" "30"
"Sep" "0"
"Oct" "19"
"Nov" "123"
"Dec" "410"
Consider the following table
mysql> select * from cart ;
+------+------------+-------------+
| id | date | total_price |
+------+------------+-------------+
| 1 | 2014-01-01 | 10 |
| 2 | 2014-01-20 | 20 |
| 3 | 2014-02-03 | 30 |
| 4 | 2014-02-28 | 40 |
| 5 | 2014-06-01 | 50 |
| 6 | 2014-06-13 | 24 |
| 7 | 2014-12-12 | 45 |
| 8 | 2014-12-18 | 10 |
+------+------------+-------------+
Now as per the logic you are looking back one year and december will appear twice in the result i.e. dec 2013 and dec 2014 and if we need to have a separate count for them then we can use the following technique of generating dynamic date range MySql Single Table, Select last 7 days and include empty rows
t1.month,
t1.md,
coalesce(SUM(t1.amount+t2.amount), 0) AS total
from
(
select DATE_FORMAT(a.Date,"%b") as month,
DATE_FORMAT(a.Date, "%m-%Y") as md,
'0' as amount
from (
select curdate() - INTERVAL (a.a + (10 * b.a) + (100 * c.a)) DAY as Date
from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
) a
where a.Date <= NOW() and a.Date >= Date_add(Now(),interval - 12 month)
group by md
)t1
left join
(
SELECT DATE_FORMAT(date, "%b") AS month, SUM(total_price) as amount ,DATE_FORMAT(date, "%m-%Y") as md
FROM cart
where Date <= NOW() and Date >= Date_add(Now(),interval - 12 month)
GROUP BY md
)t2
on t2.md = t1.md
group by t1.md
order by t1.md
;
Output will be
+-------+---------+-------+
| month | md | total |
+-------+---------+-------+
| Jan | 01-2014 | 30 |
| Feb | 02-2014 | 70 |
| Mar | 03-2014 | 0 |
| Apr | 04-2014 | 0 |
| May | 05-2014 | 0 |
| Jun | 06-2014 | 74 |
| Jul | 07-2014 | 0 |
| Aug | 08-2014 | 0 |
| Sep | 09-2014 | 0 |
| Oct | 10-2014 | 0 |
| Nov | 11-2014 | 0 |
| Dec | 12-2013 | 0 |
| Dec | 12-2014 | 55 |
+-------+---------+-------+
13 rows in set (0.00 sec)
And if you do not care about the above case i.e. dec 2014 and dec 2013
Then just change the group by in dynamic date part as
where a.Date <= NOW() and a.Date >= Date_add(Now(),interval - 12 month)
group by month
and final group by as group by t1.month
Thanks for #pankaj hint, Here i resolved it via this query...
SELECT
SUM(IF(month = 'Jan', total, 0)) AS 'Jan',
SUM(IF(month = 'Feb', total, 0)) AS 'Feb',
SUM(IF(month = 'Mar', total, 0)) AS 'Mar',
SUM(IF(month = 'Apr', total, 0)) AS 'Apr',
SUM(IF(month = 'May', total, 0)) AS 'May',
SUM(IF(month = 'Jun', total, 0)) AS 'Jun',
SUM(IF(month = 'Jul', total, 0)) AS 'Jul',
SUM(IF(month = 'Aug', total, 0)) AS 'Aug',
SUM(IF(month = 'Sep', total, 0)) AS 'Sep',
SUM(IF(month = 'Oct', total, 0)) AS 'Oct',
SUM(IF(month = 'Nov', total, 0)) AS 'Nov',
SUM(IF(month = 'Dec', total, 0)) AS 'Dec',
SUM(total) AS total_yearly
FROM (
SELECT DATE_FORMAT(date, "%b") AS month, SUM(total_price) as total
FROM cart
WHERE date <= NOW() and date >= Date_add(Now(),interval - 12 month)
GROUP BY DATE_FORMAT(date, "%m-%Y")) as sub
Month wise sale
Use Count to count month wise data.
SELECT DATE_FORMAT(date, "%b") AS month, COUNT(total_price) as total
FROM cart
WHERE date <= NOW()
and date >= Date_add(Now(),interval - 12 month)
GROUP BY DATE_FORMAT(date, "%m-%Y")

Generate report by month and year in mysql

I need to generate a report 12 months before the current date.
Today is 2014-04-29. So my date range would be 2013-04-29 to 2014-04-29.
These is my sample data:
--------------------------------------
-- user_id | lead_id | date_entered --
-- 1 | 1 | 2013-12-05 --
-- 1 | 2 | 2014-03-15 --
-- 1 | 3 | 2014-04-24 --
--------------------------------------
Expected output should be:
--------------------------
-- month | year | total --
-- Apr | 2013 | 0 --
-- May | 2013 | 0 --
-- Jun | 2013 | 0 --
-- Jul | 2013 | 0 --
-- Aug | 2013 | 0 --
-- Sep | 2013 | 0 --
-- Oct | 2013 | 0 --
-- Nov | 2013 | 0 --
-- Dec | 2013 | 1 --
-- Jan | 2014 | 0 --
-- Feb | 2014 | 0 --
-- Mar | 2014 | 1 --
-- Apr | 2014 | 1 --
--------------------------
Here is my query:
select a.month, a.year, IFNULL(d.total, 0) AS total
from (
SELECT 'Apr' month, 2013 year, 1 monthOrder UNION
SELECT 'May' month, 2013 year, 2 monthOrder UNION
SELECT 'Jun' month, 2013 year, 3 monthOrder UNION
SELECT 'Jul' month, 2013 year, 4 monthOrder UNION
SELECT 'Aug' month, 2013 year, 5 monthOrder UNION
SELECT 'Sep' month, 2013 year, 6 monthOrder UNION
SELECT 'Oct' month, 2013 year, 7 monthOrder UNION
SELECT 'Nov' month, 2013 year, 8 monthOrder UNION
SELECT 'Dec' month, 2013 year, 9 monthOrder UNION
SELECT 'Jan' month, 2014 year, 10 monthOrder UNION
SELECT 'Feb' month, 2014 year, 11 monthOrder UNION
SELECT 'Mar' month, 2014 year, 12 monthOrder UNION
SELECT 'Apr' month, 2014 year, 13 monthOrder
) AS a left join (
SELECT date_entered, count(id) AS total
FROM leads AS b
WHERE user_id = 1
AND is_deleted = 0
AND date_entered BETWEEN "2013-04-29" AND "2014-04-29"
GROUP BY YEAR(b.date_entered), MONTH(b.date_entered)
) AS d on a.month = DATE_FORMAT(d.date_entered, "%b")
ORDER BY a.monthOrder asc
My query's output:
--------------------------
-- month | year | total --
-- Apr | 2013 | 1 --
-- May | 2013 | 0 --
-- Jun | 2013 | 0 --
-- Jul | 2013 | 0 --
-- Aug | 2013 | 0 --
-- Sep | 2013 | 0 --
-- Oct | 2013 | 0 --
-- Nov | 2013 | 0 --
-- Dec | 2013 | 1 --
-- Jan | 2014 | 0 --
-- Feb | 2014 | 0 --
-- Mar | 2014 | 1 --
-- Apr | 2014 | 1 --
--------------------------
Because on my on a.month = DATE_FORMAT(d.date_entered, "%b") I compare the month that's why Apr 2013 has a total 1. How do I fix this issue? Can someone help me?
is there a way I can compare both month and year? How do I do that?
Thanks
I think you should simplify and use this hack...
basically you format the date in year/month format and group by it as a string, and count.
This query alone should give you all the report you need.
select
concat( DATE_FORMAT(date_entered ,'%Y%m')) as `yearmonth`,
count(*) as `total`
from
leads
where
user_id=1 and
is_deleted = 0 and
date_entered BETWEEN "2013-04-29" AND "2014-04-29"
group by 1
order by date_entered
Try it and tune it according to your needs.
Do not add other columns because it will group by those too and you will get wrong results.
You need to query year on grouping too, using WHERE a.year=DATE_FORMAT(d.date_entered, "%Y") as extra condition at top select level.
select a.month, a.year, IFNULL(d.total, 0) AS total
from (
SELECT 'Apr' month, 2013 year, 1 monthOrder UNION
SELECT 'May' month, 2013 year, 2 monthOrder UNION
SELECT 'Jun' month, 2013 year, 3 monthOrder UNION
SELECT 'Jul' month, 2013 year, 4 monthOrder UNION
SELECT 'Aug' month, 2013 year, 5 monthOrder UNION
SELECT 'Sep' month, 2013 year, 6 monthOrder UNION
SELECT 'Oct' month, 2013 year, 7 monthOrder UNION
SELECT 'Nov' month, 2013 year, 8 monthOrder UNION
SELECT 'Dec' month, 2013 year, 9 monthOrder UNION
SELECT 'Jan' month, 2014 year, 10 monthOrder UNION
SELECT 'Feb' month, 2014 year, 11 monthOrder UNION
SELECT 'Mar' month, 2014 year, 12 monthOrder UNION
SELECT 'Apr' month, 2014 year, 13 monthOrder
) AS a left join (
SELECT date_entered, count(id) AS total
FROM leads AS b
WHERE user_id = 1
AND is_deleted = 0
AND date_entered BETWEEN "2013-04-29" AND "2014-04-29"
GROUP BY YEAR(b.date_entered), MONTH(b.date_entered)
) AS d on a.month = DATE_FORMAT(d.date_entered, "%b")
WHERE a.year=DATE_FORMAT(d.date_entered, "%Y") -- this added
ORDER BY a.monthOrder asc
Or use AND instead of WHERE, this should have the same effectm as proposed in comments. on a.month = DATE_FORMAT(d.date_entered, "%b") AND a.year=DATE_FORMAT(d.date_entered, "%Y")
You can match 2 fields with join as per below:
SELECT a.month, a.year, IFNULL(d.total, 0) AS total
FROM (
SELECT 'Apr' MONTH, 2013 YEAR, 1 monthOrder UNION
SELECT 'May' MONTH, 2013 YEAR, 2 monthOrder UNION
SELECT 'Jun' MONTH, 2013 YEAR, 3 monthOrder UNION
SELECT 'Jul' MONTH, 2013 YEAR, 4 monthOrder UNION
SELECT 'Aug' MONTH, 2013 YEAR, 5 monthOrder UNION
SELECT 'Sep' MONTH, 2013 YEAR, 6 monthOrder UNION
SELECT 'Oct' MONTH, 2013 YEAR, 7 monthOrder UNION
SELECT 'Nov' MONTH, 2013 YEAR, 8 monthOrder UNION
SELECT 'Dec' MONTH, 2013 YEAR, 9 monthOrder UNION
SELECT 'Jan' MONTH, 2014 YEAR, 10 monthOrder UNION
SELECT 'Feb' MONTH, 2014 YEAR, 11 monthOrder UNION
SELECT 'Mar' MONTH, 2014 YEAR, 12 monthOrder UNION
SELECT 'Apr' MONTH, 2014 YEAR, 13 monthOrder
) AS a LEFT JOIN (
SELECT date_entered, COUNT(id) AS total
FROM leads AS b
WHERE user_id = 1
AND is_deleted = 0
AND date_entered BETWEEN "2013-04-29" AND "2014-04-29"
GROUP BY YEAR(b.date_entered), MONTH(b.date_entered)
) AS d ON a.month = DATE_FORMAT(d.date_entered, "%b") AND a.YEAR = DATE_FORMAT(d.date_entered, "%Y")
ORDER BY a.monthOrder ASC

SUM DISTINCT MYSQL | WHERE CLAUSE

I would like to get results based on SUM from table (history), where username contains 'red' and grouped by month. here the query :
select month(date),
SUM(CASE WHEN status='success' THEN 1 ELSE 0 END) as total_sucess,
SUM(CASE WHEN status='failed' THEN 1 ELSE 0 END) as total_failed
from history
where date between '201305%' AND '201311%' AND username like '%#red%'
GROUP BY month(history.date);
the results :
+------------+--------------+--------------+
| month(date) | total_sucess | total_failed |
+------------+--------------+--------------+
| 5 | 10960 | 3573 |
| 6 | 2336 | 1202 |
| 7 | 2211 | 1830 |
| 8 | 5312 | 3125 |
| 9 | 9844 | 5407 |
| 10 | 6351 | 3972 |
+------------+--------------+--------------+
the question is , how do I get distinct total_success and total_failed SUM? just in one query ?
I've tried using this
select month(tgl),
SUM(CASE WHEN status='success' THEN 1 ELSE 0 END) as total_sucess,
SUM(DISTINCT (username) CASE WHEN status='success' THEN 1 ELSE 0 END) as distinct_total_sucess,
SUM(CASE WHEN status='failed' THEN 1 ELSE 0 END) as total_failed,
SUM(DISTINCT (username) CASE WHEN status='failed' THEN 1 ELSE 0 END) as distinct_failed_sucess
from history_auth
where tgl between '201305%' AND '201311%' AND username like '%#t.sel%'
GROUP BY month(history_auth.tgl);
but get error sql syntax... i have no idea with this :(
Best I can make out of your requirement is that you want the number of distinct usernames each month that succeeded / failed.
If so I think you need a pair of sub selects to get those figures.
Rejigged the query (adding another sub select to get the 6 months, rather than relying on all months being represented.
SELECT Sub1.aMonth,
SUM(CASE WHEN history.status='success' THEN 1 ELSE 0 END) as total_sucess,
SUM(CASE WHEN history.status='failed' THEN 1 ELSE 0 END) as total_failed,
IFNULL(SuccessCount, 0),
IFNULL(FailedCount, 0)
FROM
(
SELECT MONTH(DATE_SUB('2013-11-01', INTERVAL 0 MONTH)) AS aMonth
UNION SELECT MONTH(DATE_SUB('2013-11-01', INTERVAL 1 MONTH))
UNION SELECT MONTH(DATE_SUB('2013-11-01', INTERVAL 2 MONTH))
UNION SELECT MONTH(DATE_SUB('2013-11-01', INTERVAL 3 MONTH))
UNION SELECT MONTH(DATE_SUB('2013-11-01', INTERVAL 4 MONTH))
UNION SELECT MONTH(DATE_SUB('2013-11-01', INTERVAL 5 MONTH))
UNION SELECT MONTH(DATE_SUB('2013-11-01', INTERVAL 6 MONTH))
) Sub1
LEFT OUTER JOIN history
ON MONTH(history.date) = Sub1.aMonth
AND username LIKE '%#red%'
LEFT OUTER JOIN
(
SELECT MONTH(date) AS aMonth, COUNT(DISTINCT username) AS SuccessCount
FROM history
WHERE status='success'
AND username LIKE '%#red%'
GROUP BY MONTH(date)
) Sub2
ON Sub1.aMonth = Sub2.aMonth
LEFT OUTER JOIN
(
SELECT MONTH(date) AS aMonth, COUNT(DISTINCT username) AS FailedCount
FROM history
WHERE status='failed'
AND username LIKE '%#red%'
GROUP BY MONTH(date)
) Sub3
ON Sub1.aMonth = Sub3.aMonth
GROUP BY Sub1.aMonth, SuccessCount, FailedCount

How can I GROUP BY more than one row/column?

I'm looking for a way to group more than one column in mysql.
The table is pretty much:
Customer, Product, Date
Joe, Apple, 2011-01-01
Henry, Banana, 2011-05-26
Sally, Peach, 2011-06-02
Jane, Strawberry, 2010-06-25
What I wanna do is count the NUMBER of Produkts each customer bought and group that by the month of the year.
So it would look like.
COUNT(Product) | January | February | March ....... | Total
If I just use GROUP BY product, MONTH(date) I get
Banana, January, 2
Banana, February, 3
Banana, March, 1
and so on.
Is there a way to do this, so that I get as many rows as I have distinct products and then a column for each month?
I'm really trying NOT to do this lateron in PHP because it get's incredibly slow.
Thanks a lot, already!
SELECT Product,
SUM(CASE WHEN MONTH(date) = 1 THEN 1 ELSE 0 END) Jan,
SUM(CASE WHEN MONTH(date) = 2 THEN 1 ELSE 0 END) Feb,
SUM(CASE WHEN MONTH(date) = 3 THEN 1 ELSE 0 END) Mar,
SUM(CASE WHEN MONTH(date) = 4 THEN 1 ELSE 0 END) Apr,
SUM(CASE WHEN MONTH(date) = 5 THEN 1 ELSE 0 END) May,
SUM(CASE WHEN MONTH(date) = 6 THEN 1 ELSE 0 END) Jun,
SUM(CASE WHEN MONTH(date) = 7 THEN 1 ELSE 0 END) Jul,
SUM(CASE WHEN MONTH(date) = 8 THEN 1 ELSE 0 END) Aug,
SUM(CASE WHEN MONTH(date) = 9 THEN 1 ELSE 0 END) Sep,
SUM(CASE WHEN MONTH(date) = 10 THEN 1 ELSE 0 END) Oct,
SUM(CASE WHEN MONTH(date) = 11 THEN 1 ELSE 0 END) Nov,
SUM(CASE WHEN MONTH(date) = 12 THEN 1 ELSE 0 END) Dec,
COUNT(date) Total
FROM
MyTable
GROUP BY
product