MySQL Sum operation based on other column - mysql

I have a table like this:
Date | Name | Pick | Amount
-----------+-------+-------+-------
2018-01-01 | Alice | Apple | 2
2018-01-01 | Alice | Grape | 3
2018-01-01 | Bob | Apple | 4
2018-01-02 | Alice | Apple | 5
2018-01-02 | Bob | Grape | 6
What is the SQL statement that produce result like below?
Name | Apple | Grape | Total
------+-------+-------+------
Alice | 7 | 3 | 10
Bob | 4 | 6 | 10

Using CASE condition, it will be possible.
Try this:
select name
,sum(case when pick = 'Apple' then amount end)Apple
,sum(case when pick = 'Grape' then amount end)Grape
,sum(case when pick = 'Apple' then amount end)
+sum(case when pick = 'Grape' then amount end)Total
from your_table
group by name

You want conditional aggregation :
select name,
sum(case when pick = 'Apple' then amount else 0 end) Apple,
sum(case when pick = 'Grape' then amount else 0 end) Grape,
sum(case when pick in ('Apple', 'Grape') then amount else 0 end) Total
from table t
group by name;

the is also a way to calculate your result, using aggregate function and or
select name,
sum(case when pick = 'Apple' then amount else 0 end) Apple,
sum(case when pick = 'Grape' then amount else 0 end) Grape,
sum(case when pick in('Apple','Grape') then amount else 0 end) Total
from tableA
group by name
http://sqlfiddle.com/#!9/4c56c/4

SELECT Name,
sum(if(Pick='Apple', Amount, 0)) as Apple,
sum(if(Pick='Grape', amount, 0)) as Grape
FROM table_name
GROUP BY Name;

You can use nested queries. One to calculate the grapes and the apples and one to calculate the total. The advantage is that you have the logic for calculation of each column on a single place and the calculation of the total is a bit more visible
SELECT
Name,
Apple,
Grape,
Apple + Grape as Total
FROM (
SELECT
`name` as Name,
SUM(IF(pick = 'Apple', amount, 0)) as Apple,
SUM(IF(pick = 'Grape', amount, 0)) as Grape
FROM test
GROUP BY name
) AS t1
db-fiddle

Related

MySQL row into number of columns and sum

Could somebody help with my SQL?
I have a table with records such as:
ID | Car_num | Service | Price
---+---------+---------+------
1 | 001 | shower | 10
2 | 002 | TV | 5
3 | 001 | TV | 5
How to write an SQL query to get the following output?
ID |Car_num | shower | TV
---+--------+--------+---
1 | 001 | 10 | 5
2 | 002 | 0 | 5
Use a pivot query:
SELECT MIN(ID) AS ID,
Car_num,
MAX(CASE WHEN Service = 'shower' THEN Price ELSE 0 END) AS shower,
MAX(CASE WHEN Service = 'TV' THEN Price ELSE 0 END) AS TV
FROM yourTable
GROUP BY Car_num
SELECT ROW_NUMBER() OVER(ORDER BY Car_num) Id,Car_num ,ISNULL([TV],0) [TV],ISNULL([shower],0) [shower]
FROM
(
SELECT Car_num , _Service , ISNULL(Price,0) Price
FROM #Table
)Data
PIVOT
(
MAX(Price) FOR _Service IN ([TV],[shower])
)AS PVT
Try this:
SELECT ID, Car_num
, SUM(IF(Service = 'shower', Price, 0)) AS Shower
, SUM(IF(Service = 'TV', Price, 0)) AS TV
FROM your_table
GROUP BY Car_num;

MySQL - Count values of a column ordered by other column

I want to achieve this table:
|Country|Cars|Blue Cars|Red Cars| Green Cars |
|Mexico | 22 | 12 | 8 | 2 |
|U.S.A | 12 | 6 | 3 | 3 |
|Denmark| 10 | 3 | 2 | 5 |
That from a database table that makes a report (row) for every car, like this:
|Country|car_color|
|Mexico | Blue |
|U.S.A | Red |
|Denmark| Blue |
|Denmark| Blue |
|Mexico | Blue |
|Denmark| Green |
|Denmark| Red |
|U.S.A | Red |
|Denmark| Green |
I did the first part: grouping the countries and get the total number of cars by country, that was with this query:
SELECT country,
COUNT(county)
FROM my_table
GROUP BY country
ORDER BY COUNT(country)
My question is, how do I get the color car columns in the first table after grouping the rows by county and getting the total number of cars by every country?
Note: I tried several ways but I'm failing to achieve this. As an example, I used:
SELECT country,
COUNT(country),
COUNT(case when car_color = 'Green' then 1 else 0 end)
FROM my_table
GROUP BY country
ORDER BY COUNT(country)
But that only shows the same value of Cars (total number of cars in a country) for the column "Green Car".
Help please!
COUNT counts non-NULL rows and your CASE always returns a value.
Either switch to SUM or omit the ELSE part:
SELECT country
,COUNT(*) AS cars
,SUM(case when car_color = "blue" then 1 else 0 end) AS "blue cars"
,SUM(case when car_color = "red" then 1 else 0 end) AS "red cars"
,COUNT(case when car_color = "green" then 1 end) AS "green cars"
FROM my_table
GROUP BY country
ORDER BY COUNT(*) DESC

MySQL multi join / group query

idI have a table like this
|----|-----------|--------|
| ID | Ethnicity | Gender |
| 1 | 2 | 1 |
| 2 | 3 | 1 |
| 3 | 4 | 2 |
|----|-----------|--------|
etc ....
And I'm trying to get back a set of results that show me ethnicities group by male(1) and female(2)
So the result row would in this example would be:
Ethnicity Male Female
2 1 0
3 1 0
4 0 1
So far I'm close with to what I want with:
SELECT ethnicity,
(SELECT
count(id)
FROM
table_name
WHERE
gender = '2' ) as female,
(SELECT
count(id)
FROM
table_name
WHERE
gender = '1') as male
FROM table_name
GROUP BY ethnicity
Which gives me:
Ethnicity Male Female
2 2 1
3 2 1
4 2 1
But need the count(id) to only be a count of the adno of that ethnicity row if that makes sense.
Try this instead:
SELECT
ethnicity,
SUM(CASE WHEN gender = 1 THEN 1 ELSE 0 END) AS female,
SUM(CASE WHEN gender = 2 THEN 1 ELSE 0 END) AS Male
FROM students
GROUP BY ethnicity;
The above should work in virtually any SQL product, not just in MySQL. If you like, however, you can also use this version, which employs MySQL's implicit conversion of booleans to ints (true -> 1, false -> 0):
SELECT
ethnicity,
SUM(gender = 1) AS female,
SUM(gender = 2) AS Male
FROM students
GROUP BY ethnicity;
SELECT
ethnicity,
CASE WHEN gender = 1 THEN 1 ELSE 0 END AS Male,
CASE WHEN gender = 2 THEN 1 ELSE 0 END AS Female
FROM students

Double group by

I've got table with two columns: name and grade. It looks sth like this:
NAME | GRADE
Adam | 1
Adam | 2
Adam | 2
Adam | 3
Frank | 2
Frank | 1
Now I want create view that will looks like this:
NAME | GRADE 1 | GRADE 2 | GRADE 3
Adam | 1 | 2 | 1
Frank | 1 | 1 | 0
I've wrote this:
SELECT Name,
(SELECT COUNT(Grade)
FROM dbo.Rodzaj
WHERE Grade = '1') as Grade_1,
(SELECT COUNT(Grade)
FROM dbo.Rodzaj
WHERE Grade = '2) as Grade_2,
(SELECT COUNT(Grade)
FROM dbo.Rodzaj
WHERE Grade = '3') as Grade_3
FROM dbo.Rodzaj
GROUP BY Name
but it doesn't work...
I would appreciate any help
What you are looking for is called a "pivot table" and it is done with a chain of CASE statements which apply a 1 or 0 for each condition, then SUM() up the ones and zeros to retrieve a count.
SELECT
NAME,
SUM(CASE WHEN GRADE = 1 THEN 1 ELSE 0 END) AS GRADE1,
SUM(CASE WHEN GRADE = 2 THEN 1 ELSE 0 END) AS GRADE2,
SUM(CASE WHEN GRADE = 3 THEN 1 ELSE 0 END) AS GRADE3
FROM Rodzaj
GROUP BY NAME
Note that if you need this to have a dynamic number of columns, you will have to construct the query using a scripting language and a loop. (Or a loop inside a stored procedure)

Getting conditional counts on to the same row in MySQL / SQL

Suppose I have a table, Foo, that looks like this:
ID | Name | Gender | Team
1 | Bob | Male | A
2 | Amy | Female | A
3 | Cat | Female | B
4 | Dave | Male | B
5 | Evan | Male | B
If I wanted to get a list of the number of males and females per team on the same row, how would I do that?
I know I could do SELECT COUNT(Name) as "#", Team, Gender FROM foo GROUP BY Team, Gender, and that's fine for most purpose.
But that would give me 2 rows per team, like below, and that can be a pain.
# Team Gender
1 | A | Male
1 | A | Female
1 | B | Female
2 | B | Male
How could I structure the query such that they appear on the same row?
ie,
Team | Males | Females
A | 1 | 1
B | 2 | 1
select team,
SUM(case when gender='Male' then 1 else 0 end) Male,
SUM(case when gender='Female' then 1 else 0 end) Female
from tbl
group by team
For the comment
Imagine now that each row has an arbitrary numeric score associated with it, in a Score column. How would I have 'Male points' and 'Female points? Would that be SUM(case when gender="male" then select points else 0 end) "Male Points"
You're close. The answer is
select team,
SUM(case when gender='Male' then 1 else 0 end) Male,
SUM(case when gender='Male' then points else 0 end) `Male Points`,
SUM(case when gender='Female' then 1 else 0 end) Female,
SUM(case when gender='Female' then points else 0 end) `Female Points`
from tbl
group by team
The pattern I was looking for was a Self-Join; the syntax and logic is, in my mind, more elegant then the CASE pattern.
Specifically,
SELECT Males.Team, COUNT(Males.id) as "Males", SUM(Males.Points) as "Male Points",
COUNT(Females.id) as "Females", SUM(Females.Points) as "Female Points"
FROM scores as Males
LEFT JOIN scores as Females ON Males.Team=Females.Team AND Females.Gender="Female"
WHERE Males.Gender="Male"
GROUP BY Team
Instead of case statements, the groupings I want in different columns get split into their own copies of the same table. You then join the table of Male players with a Table of Female players on the Team, and then group by the Team.