Sum in group by with join Mysql, multiple group by - mysql

I want to find the sum by months. The result returned 0 rows of records.
Table 1: aidat
1 Messi
2 Ronaldo
3 Neymar
Table 2: aidat_hareket
12 1(messi) 200 12-12-2018
13 3 150 12-11-2018
14 2 25 10-10-2018
15 1 150 10-12-2018
16 3 125 08-05-2018
I want to result this:
id name jan feb march april may ... oct nov dec
1 messi 0 0 0 0 0 0 0 350
2 ronaldo 0 0 0 0 0 25 0 0
3 neymar 0 0 0 0 125 0 150 0
it returned 0 rows in mysql. I tried group by month(ah.datee) and a.student_id; , month(ah.datee), a.student_id; and a.student_id; in inner join. But result is the same.
SELECT o.id as o_id, o.ad, s.ad as s_ad, s.plaka, v.id as veli_id,v.ad as
veli_ad, v.telefon,s.demo,
if(month(ah.datee)=1 , ah.collection,0) as jan,
if(month(ah.datee)=2 , ah.collection,0) as feb,
if(month(ah.datee)=3 , ah.collection,0) as march,
if(month(ah.datee)=4 , ah.collection,0) as april,
if(month(ah.datee)=5 , ah.collection,0) as may,
if(month(ah.datee)=6 , ah.collection,0) as june,
if(month(ah.datee)=7 , ah.collection,0) as july,
if(month(ah.datee)=8 , ah.collection,0) as august,
if(month(ah.datee)=9 , ah.collection,0) as sep,
if(month(ah.datee)=10, ah.collection,0) as oct,
if(month(ah.datee)=11, ah.collection,0) as nov,
if(month(ah.datee)=12, ah.collection,0) as december
from aidat a
inner join (select student_id, sum(collection_tutari) as collection, collection_datee as datee from aidat_hareket )
ah on ah.student_id = a.student_id
inner join student o on o.id = a.student_id
inner join service s on s.id = o.service_id
inner join service_firma sf on sf.id = s.firma_id
left join aile al on al.student_id = a.student_id
left join veli v on v.id = al.veli_id
inner join aylar ay on ay.id = month(ah.datee)
where a.aylik_odeme_tutari != 0 and sf.id = 23
group by month(ah.datee), a.student_id;
How can I fixed it?

Related

SQL JOIN, GROUP BY on Four tables to get Record By Month

I have the following DB design. Tables are:
auth_user
----------
first_name
last_name
staffuser
----------
phone_number
user_id
billing_customerservicebill
-----------------------------
bill_id
service_provider_id
discounted_price
billing_billmanagement
------------------------
creation_date
My query return Sum of discounted_price each user by month row wise. I need every month record show in column.
The following query gives me This record
select a.service_provider_id, first_name, Sum(a.discounted_price), EXTRACT(MONTH FROM c.creation_date)
from billing_customerservicebill a
left outer join users_staffuser b
on a.service_provider_id = b.id
left outer join billing_billmanagement c
on a.bill_id = c.id
left outer join auth_user d
on d.id = b.user_id
where c.creation_date between '2017-11-01' AND '2017-12-31'
group by service_provider_id, first_name, EXTRACT(MONTH FROM c.creation_date)
order by 1
My data show in Table Currently
service_provider_id | first_name | Sum | Month
5 | suneel 31500 | 11
5 | Suneel | 900 | 12
Expected data is
service_provider_id | first_name | Nov | December
5 | suneel | 31500 | 900
The most flexible approach is to use conditional aggregation...
select
a.service_provider_id,
first_name,
SUM(CASE WHEN c.creation_date >= '2017-11-01' AND c.creation_date < '2017-12-01' THEN a.discounted_price END) AS nov,
SUM(CASE WHEN c.creation_date >= '2017-12-01' AND c.creation_date < '2018-01-01' THEN a.discounted_price END) AS dec
from billing_customerservicebill a
left outer join users_staffuser b
on a.service_provider_id = b.id
left outer join billing_billmanagement c
on a.bill_id = c.id
left outer join auth_user d
on d.id = b.user_id
where c.creation_date between '2017-11-01' AND '2017-12-31'
group by service_provider_id, first_name
order by 1
This shows that you need to know in advance which columns you're going to calculate.
Please, try with below solution it's near to your answer:
Where month as column and group by users:
select B.service_provider_id, B.first_name,
(case when month=1 then discounted_price else 0 end) as JAN,
(case when month=2 then discounted_price else 0 end) as FEB,
(case when month=3 then discounted_price else 0 end) as MAR,
(case when month=4 then discounted_price else 0 end) as APR,
(case when month=5 then discounted_price else 0 end) as MAY,
(case when month=6 then discounted_price else 0 end) as JUN,
(case when month=7 then discounted_price else 0 end) as JULY,
(case when month=8 then discounted_price else 0 end) as AUG,
(case when month=9 then discounted_price else 0 end) as SEP,
(case when month=10 then discounted_price else 0 end) as OCT,
(case when month=11 then discounted_price else 0 end) as NOV,
(case when month=12 then discounted_price else 0 end) as DEC
from(
select a.service_provider_id, first_name, Sum(a.discounted_price) as discounted_price, EXTRACT(MONTH FROM c.creation_date) as month
from billing_customerservicebill a
left outer join users_staffuser b
on a.service_provider_id = b.id
left outer join billing_billmanagement c
on a.bill_id = c.id
left outer join auth_user d
on d.id = b.user_id
where c.creation_date between '2017-11-01' AND '2017-12-31'
group by service_provider_id, first_name, EXTRACT(MONTH FROM c.creation_date)
) as B
group by B.service_provider_id, B.first_name

SUM total by year per user, group by user, dynamic columns for each year

This query was given to me and I need to make it dynamic so the year columns aren't hard-coded:
SELECT u.last_name as 'Name',
COUNT(e.user_id) as 'Total',
SUM(CASE WHEN YEAR(e.datetime)=2012 THEN 1 END) as '2012',
SUM(CASE WHEN YEAR(e.datetime)=2013 THEN 1 END) as '2013',
SUM(CASE WHEN YEAR(e.datetime)=2014 THEN 1 END) as '2014',
SUM(CASE WHEN YEAR(e.datetime)=2015 THEN 1 END) as '2015',
SUM(CASE WHEN YEAR(e.datetime)=2016 THEN 1 END) as '2016'
FROM entries e, users u
WHERE e.user_id = u.user_id
GROUP BY e.user_id
Is there any way to create the year columns dynamically, and sum them dynamically using just mysql? I can of course do it with some php, but wondering if it's possible in pure mysql.
The current query outputs something like:
Name Total 2012 2013 2014 2015 2016
Smith 568 186 124 162 75 21
Jones 579 188 156 160 68 7
You could loop round the results like this
$d = 2016;
$string = '';
for($i = 2012; $i <= $d; $i ++) {
$string .= "SUM(CASE WHEN YEAR(e.datetime)=$i THEN 1 END) as '$i'";
}
Then add it to the query
SELECT u.last_name as 'Name',
COUNT(e.user_id) as 'Total',
'.$string.'
FROM entries e, users u
WHERE e.user_id = u.user_id
GROUP BY e.user_id

Why MySQL full outer join returns nulls?

Why MySQL full outer join returns nulls?
Hi
I have the following data:
s_id,date,p_id,amount_sold
1, '2015-10-01', 1, 10
2, '2015-10-01', 2, 12
7, '2015-10-01', 1, 11
3, '2015-10-02', 1, 11
4, '2015-10-02', 2, 10
5, '2015-10-15', 1, 22
6, '2015-10-16', 2, 20
8, '2015-10-22', 3, 444
and i want my query to output something like this: (A = sum of amount_sold for p_id=1 for that date,B = sum of amount_sold for p_id=2 for that date)
date,A,B,Difference
'2015-10-01',21,12,9
'2015-10-02',11,10,1
'2015-10-15',22,0,22
'2015-10-01',0,20,-20
I tried with this query, but the order its returning is having NULLS and the output is wrong:
SELECT A.p_id,A.date,sum(A.amount_sold) A,B.Bs, (sum(A.amount_sold) - B.Bs) as difference FROM sales as A
LEFT JOIN (
SELECT SUM( amount_sold ) Bs,p_id,s_id, DATE
FROM sales
WHERE p_id =2
group by date
) as B ON A.s_id = B.s_id
where A.p_id=1 or B.p_id=2
group by A.date, A.p_id
UNION
SELECT A.p_id,A.date,sum(A.amount_sold) A,B.Bs, (sum(A.amount_sold) - B.Bs) as difference FROM sales as A
RIGHT JOIN (
SELECT SUM( amount_sold ) Bs,p_id,s_id, DATE
FROM sales
WHERE p_id =2
group by date
) as B ON A.s_id = B.s_id
where B.p_id=2
group by A.date, A.p_id
It returned:
p_id date A Bs difference
1 2015-10-01 21 NULL NULL
2 2015-10-01 12 12 0
1 2015-10-02 11 NULL NULL
2 2015-10-02 10 10 0
1 2015-10-15 22 NULL NULL
2 2015-10-16 20 20 0
What am i doing wrong here? and what is the correct way of doing it? any help would be appreciated.
A full join isn't needed. You can use conditional aggregation instead:
select
date,
sum(case when p_id = 1 then amount_sold else 0 end) a,
sum(case when p_id = 2 then amount_sold else 0 end) b,
sum(case when p_id = 1 then amount_sold else 0 end)
- sum(case when p_id = 2 then amount_sold else 0 end) difference
from sales
where p_id in (1,2)
group by date

add sum of all values mysql query

select(sum(
if (lower(st.c_gender) = 'male', 1, 0)) - ifnull(le.male, 0)) as male, (sum(
if (lower(st.c_gender) = 'female', 1, 0)) - ifnull(le.female, 0)) as female, FROM_UNIXTIME(st.c_admissionDate, '%Y') as year, le.male, le.female
from(SELECT s.*, zone.id as zoneid FROM groups s left join groups as zone ON s.parent_id = zone.id where s.id != s.parent_id) g, group_to_user u, student st
left join(SELECT ifnull(sum(
if (lower(l.c_gender) = 'male', 1, 0)), 0) as male, ifnull(sum(
if (lower(l.c_gender) = 'female', 1, 0)), 0) as female, FROM_UNIXTIME(l.c_leavingDate, '%Y') as year from student l
where l.c_leavingDate is not null group by FROM_UNIXTIME(l.c_leavingDate, '%Y')) as le on le.year = FROM_UNIXTIME(st.c_admissionDate, '%Y')
where g.id = u.groupid and st.c_userId = u.userId group by FROM_UNIXTIME(st.c_admissionDate, '%Y')
the above query returns the following output ,
male female year male female
1860 657 1970 NULL NULL
2 4 2012 NULL NULL
3 0 2013 NULL NULL
470 370 2014 0 1
0 365 2015 NULL NULL
0 367 2016 NULL NULL
1 260 2017 1 2
from the above output need to sum the before values like the following output
male female year male female
1860 657 1970 NULL NULL
1862 661 2012 NULL NULL
1865 661 2013 NULL NULL
2335 1031 2014 0 1
2335 1396 2015 NULL NULL
2335 1763 2016 NULL NULL
2336 2023 2017 1 2
anyway to make the output like the above help me
set #msum := 0;
set #fsum := 0;
select (#msum := #msum + T.male_sum) as male_sum, (#fsum := #fsum + T.female_sum) as female_sum, T.year, T.male, T.female
from (
select(sum(
if (lower(st.c_gender) = 'male', 1, 0)) - ifnull(le.male, 0)) as male_sum, (sum(
if (lower(st.c_gender) = 'female', 1, 0)) - ifnull(le.female, 0)) as female_sum, FROM_UNIXTIME(st.c_admissionDate, '%Y') as year, le.male, le.female
from(SELECT s.*, zone.id as zoneid FROM groups s left join groups as zone ON s.parent_id = zone.id where s.id != s.parent_id) g, group_to_user u, student st
left join(SELECT ifnull(sum(
if (lower(l.c_gender) = 'male', 1, 0)), 0) as male, ifnull(sum(
if (lower(l.c_gender) = 'female', 1, 0)), 0) as female, FROM_UNIXTIME(l.c_leavingDate, '%Y') as year from student l
where l.c_leavingDate is not null group by FROM_UNIXTIME(l.c_leavingDate, '%Y')) as le on le.year = FROM_UNIXTIME(st.c_admissionDate, '%Y')
where g.id = u.groupid and st.c_userId = u.userId group by FROM_UNIXTIME(st.c_admissionDate, '%Y')
)T;
Simplify this query but this will give you a general idea. Cannot be done in a non procedural query.
You really need a column for a reliable ordering.
But a method in MySQL is to use # variables like this.
SELECT
#male = #male + male as male
, #female = #female + female as female
, ordering_column
FROM (
<< your existing query here >>
)
CROSS JOIN ( SELECT #male := 0 m, #female := 0 f ) vars
ORDER BY
ordering_column

SQL Query to get the total sales per seller by month

I try this:
SELECT
profile.user_id,
profile.name,
total_month.total as month10
FROM profile
LEFT OUTER JOIN (SELECT
order.seller_id,
COUNT(*) AS total
FROM order
WHERE MONTH(order.data_hora) = 10
GROUP BY order.seller_id) AS total_month
ON total_month.seller_id= profile.user_id;
The result was this:
-------------------------
|user_id| name |month10|
-------------------------
| 5 |user1 | 73 |
| 1 |user2 | 1 |
-------------------------
But I need more months like this:
-------------------------------------------------
| user_id | name | month10 | month11 | month12 |
-------------------------------------------------
| 5 | user1 | 73 | 52 | 65 |
| 1 | user2 | 67 | 56 | 78 |
-------------------------------------------------
How could I do this without creating a function?
You can extend your query to do what you want. Just be more flexible in the subquery:
SELECT p.user_id, p.name,
tm.month10, tm.month11, tm.month12
FROM profile p LEFT OUTER JOIN
(SELECT o.seller_id,
sum(o.data_hora = 10) as month10,
sum(o.data_hora = 11) as month11,
sum(o.data_hora = 12) as month12
FROM order o
WHERE MONTH(order.data_hora) in (10, 11, 12)
GROUP BY order.seller_id
) tm
ON tm.seller_id = p.user_id;
Well as I said in the comments supporting the #Schalk comment, in order to get this working as you want you will need a function to get a DYNAMIC PIVOT TABLE or TRANSPOSE ROWS TO COLUMNS google it if you prefer.
For your solution I've created a query that gives you all months/values like this:
user_id name jan feb mar apr may jun jul aug sep oct nov dec
1 a 0 0 1 10 0 0 1 2 7 2 3 0
2 b 1 0 0 0 2 0 0 0 3 1 1 0
If it fits to your problem this is your query:
select
profile.user_id,
profile.name,
sum(if( MONTH(orderr.data_hora) = 1, 1, 0 )) as Jan,
sum(if( MONTH(orderr.data_hora) = 2, 1, 0 )) as Feb,
sum(if( MONTH(orderr.data_hora) = 3, 1, 0 )) as Mar,
sum(if( MONTH(orderr.data_hora) = 4, 1, 0 )) as Apr,
sum(if( MONTH(orderr.data_hora) = 5, 1, 0 )) as May,
sum(if( MONTH(orderr.data_hora) = 6, 1, 0 )) as Jun,
sum(if( MONTH(orderr.data_hora) = 7, 1, 0 )) as Jul,
sum(if( MONTH(orderr.data_hora) = 8, 1, 0 )) as Aug,
sum(if( MONTH(orderr.data_hora) = 9, 1, 0 )) as Sep,
sum(if( MONTH(orderr.data_hora) = 10, 1, 0 )) as Oct,
sum(if( MONTH(orderr.data_hora) = 11, 1, 0 )) as Nov,
sum(if( MONTH(orderr.data_hora) = 12, 1, 0 )) as Dece
from
profile left join orderr
on profile.user_id = orderr.seller_id
group by profile.user_id,
profile.name
I've created a fiddle to it (but the data_hora column I created as integer to make it quickly to do it, it is for understanding).
http://sqlfiddle.com/#!2/4a1a2e/5
It was perfect!
The field type 'data_hora' is datetime, so I made a small change.
SELECT p.user_id,
p.name,
tm.month10,
tm.month11,
tm.month12,
(tm.month10+tm.month11+tm.month12) AS final_total
FROM profile p
LEFT OUTER JOIN
(SELECT o.seller_id,
sum(month(o.data_hora) = 10) AS month10,
sum(month(o.data_hora) = 11) AS month11,
sum(month(o.data_hora) = 12) AS month12
FROM order o
WHERE MONTH(ORDER.data_hora) IN (10, 11, 12)
GROUP BY ORDER.seller_id ) tm
ON tm.seller_id = p.user_id
ORDER BY final_total DESC;
How could I optimize the field "final_total"?