MySQL - Count values of a column ordered by other column - mysql

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

Related

Select count group by another count (My)SQL

Let's say I have a table that lists cars by user.
id | user_id | color
1 | 1 | red
2 | 1 | red
3 | 2 | blue
4 | 2 | red
5 | 3 | red
Now, I want to know how much red cars each client has, so I've done this SQL :
SELECT user_id, COUNT(color)
FROM cars
WHERE color = 'red'
GROUP BY user_id
Which lists me :
1 | 2
2 | 1
3 | 1
But what I really want is the count of each count. Something like :
Users with 1 red car : 2
Users with 2 red car : 1
...
So is there a way to count my select which already includes a count() grouped by ?
Thank you in advance !
Use an aggregation of aggregations:
SELECT redCount, COUNT(*)
FROM (SELECT user_id, COUNT(color) as redCount
FROM cars
WHERE color = 'red'
GROUP BY user_id
) uc
GROUP BY redCount;

Mysql subquery for group and count records by specific field

I have this problem:
I have a car table, each car record has a state field, state field value can be:
1 = Enable or 2 = Disable
For example, in this case I need to show all cars grouped by color field
and counted by color, this is not problem really :)
Here the SQL statement :
SELECT
`id`,
`model_family`,
`color`,
COUNT(`color`) AS 'quantity',
`state`
FROM `auto`
WHERE `model_family` = 'Sedan'
GROUP BY `color`
+-----+--------------+------------+----------+---+
| id | model_family | color | quantity | state |
+-----+--------------+--------+----------+-------+
| 77 | Sedan | Red | 2 | 2 |
| 42 | Sedan | Blue | 3 | 2 |
| 97 | Sedan | Green | 5 | 1 |
+-----+--------------+--------+----------+-------+
Results show two Disabled records and one Enabled record.
Well, the questions is :
How can I can show the cars disabled and enabled but
For example, if for first grouped record if state is disabled (state = 2)
then quantity field will appear as "0" (because it not exists cars enabled)
else quantity = n
Something like this:
+-----+--------------+------------+----------+-------+
| id | model_family | color | quantity | state |
+-----+--------------+------------+----------+-------+
| 77 | Sedan | Red | 0 | 2 |
| 42 | Sedan | Blue | 0 | 2 |
| 97 | Sedan | Green | 5 | 1 |
+-----+--------------+------------+----------+-------+
Regads !
SELECT
`id`,
`model_family`,
`color`,
SUM(CASE WHEN state = 1 THEN 1 ELSE 0 END) as enabled,
SUM(CASE WHEN state = 2 THEN 1 ELSE 0 END) as disabled,
`state`
FROM `auto`
WHERE `model_family` = 'Sedan'
GROUP BY `color`
You have to use case statements to group the items together. When it finds that the state is 1 you will need to sum together all of those records which is why I am doing the Then 1 Else 0.
This was a quick example of how to do it. I haven't tested to make sure it works, but it should.
If you want all disabled groups to be replaced with 0, you can just put a single case statement in your select clause. Something like this:
SELECT id, model_family, color, (CASE WHEN state = 1 THEN COUNT(*) ELSE 0 END) AS quantity, state
FROM auto
WHERE model_family = 'Sedan'
GROUP BY color
ORDER BY id;
It tested fine with your data on SQL Fiddle.
EDIT Note, since you're grouping by color, you can just use COUNT(*) instead of COUNT(color) because they are going to count the same thing.
EDIT 2 Also important to note that if a color has some enabled vehicles and some disabled vehicles, it still returns 0 because there is at least one disabled. If you want a count of the enabled ones, you can do something like this:
SELECT id, model_family, color, SUM(CASE WHEN state = 1 THEN 1 ELSE 0 END) AS quantityEnabled, state
FROM auto
WHERE model_family = 'Sedan'
GROUP BY color
ORDER BY id;
This fiddle has both examples.

SQL check multiple rows with if and get the count

Table:
id | name | country
---------------------
1 | abc | India
2 | abc | America
3 | abc | USA
4 | xyz | India
5 | xyz | America
6 | xyz | USA
QUERY tried so far:
SELECT `id`,
if(`country` = 'India',count(id),0) as object1,
if(`country` = 'America', count(id),0) as object2,
if(`country` = 'USA',count(id),0) as object3
FROM `table`
the above gives me output like this:
id | name | object1 | object2 | object3
---------------------------------------------
1 | India | 6 | 0 | 0
I want output like :
id | name | object1 | object2 | object3
---------------------------------------------
1 | India | 1 | 1 | 1
1 | America | 1 | 1 | 1
1 | USA | 1 | 1 | 1
Please someone help me out to get this output.
I think you want conditional aggregation, but it is unclear what the objects are. Based on the data, I might think:
SELECT country as name,
sum(name = 'abc') as abc,
sum(name = 'xyz') as xyz
FROM `table`
group by country;
Try this:
SELECT `id`,`country`, count(`country`) as 'CountOfCountry'
FROM `table`
GROUP by id,Country
That will give you a count of each unique country, all grouped.
This is assuming that what you are calling "objects" is really the count per country.
I am not quite sure what the third column should be because you don't have the sample data to support it. But how about the following (SQL Fiddle):
SELECT country,
SUM(CASE WHEN name = 'abc' THEN 1 ELSE 0 END) AS object1,
SUM(CASE WHEN name = 'xyz' THEN 1 ELSE 0 END) AS object2,
SUM(CASE WHEN name = 'nunya' THEN 1 ELSE 0 END) AS object3
FROM MyTable
GROUP BY country
I wasn't sure if you wanted to return the ID with your query as all the IDs in your sample output are 1, and I'm not sure how that would represent the sample data you gave, but assuming that was a typo. This is what I came up with. Here is the sql fiddle
http://sqlfiddle.com/#!6/b763d/7
select id,country,
(select count(id) from things where country='india') as object1,
(select count(id) from things where country='america') as object2,
(select count(id) from things where country='usa') as object3
from things
Now if you dont want the ID and just want things to be grouped by country then do the following.
select country,
(select count(id) from things where country='india') as object1,
(select count(id) from things where country='america') as object2,
(select count(id) from things where country='usa') as object3
from things
group by country

Condition row total as a column in another table using MySQL

Firstly, I apologize for the terrible wording, but I'm not sure how to describe what I'm doing...
I have a table of computer types (id, type, name), called com_types
id | type | name
1 | 1 | Dell
2 | 4 | HP
In a second table, I have each individual computer, with a column 'type_id' to denote what type of computer it is, called com_assets
id | type_id | is_assigned
1 | 4 | 0
2 | 1 | 1
I'd like to create a view that shows each computer type, and how many we have on hand and in use, and a total, so the outcome would be
id | type | name | on_hand | in_use | total |
1 | 1 | Dell | 0 | 1 | 1 |
2 | 4 | HP | 1 | 0 | 1 |
As you can see, the on_hand, in_use, and total columns are dependent on the type_id and is_assigned column in the second table.
So far I have tried this...
CREATE VIEW test AS
SELECT id, type, name,
( SELECT COUNT(*) FROM com_assets WHERE type_id = id AND is_assigned = '0' ) as on_hand,
( SELECT COUNT(*) FROM com_assets WHERE type_id = id AND is_assigned = '1' ) as in_use,
SUM( on_hand + in_use ) AS total
FROM com_types
But all this returns is one column with all correct values, except the total equals ALL of the computers in the other table. Will I need a trigger to do this instead?
on_hand is the count of assigned = 0, and in_use is the count of assigned = 1. You can count them together, without the correlated subqueries, like this:
SELECT
com_types.id,
com_types.type,
com_types.name,
COUNT(CASE WHEN com_assets.is_assigned = 0 THEN 1 END) AS on_hand,
COUNT(CASE WHEN com_assets.is_assigned = 1 THEN 1 END) AS in_use,
COUNT(*) AS total
FROM com_types
JOIN com_assets ON com_types.id = com_assets.id
GROUP BY
com_types.id,
com_types.type,
com_types.name

MySQL Subquery using SUM, WHERE, GROUP_BY

I'm a beginner (not a DBA).
The simple version of my data ==> My hoped for result:
|ball |color|count| |ball |Total Blue|Total Red|
------------------- ----------------------------
|b1 |red | 2 | ====> |b1 | 5 | 2 |
|b1 |blue | 3 | |b2 | 3 | 1 |
|b1 |blue | 2 |
|b2 |red | 1 |
|b2 |blue | 3 |
I want to tabulate each ball (b1, b2, etc).
Then the total instance of each color for each ball.
There are multiple entries for each color of each ball (in my real world data).
But here I show multiple entries for the blue #1-balls only.
I can easily do this:
SELECT ball,
SUM(count) AS 'Total Blue'
FROM t1
WHERE color = 'blue'
GROUP BY ball
To obtain the first (good) result:
|ball |Total Blue|
-----------------
|b1 | 5 |
|b2 | 3 |
To go further, I think I need a subquery.
But I have not been able to get the subquery to process the same way as the regular query.
Below is the closest result I've gotten so far (simple attempt):
SELECT ball,
SUM(count) AS 'Total Blue',
(SELECT SUM(count) FROM t1 WHERE color = 'red') AS 'Total Red'
FROM t1
WHERE color = 'blue'
GROUP BY ball
I get this:
|ball |Total Blue| Total Red|
---------------------------
|b1 | 5 | 3 |
|b2 | 3 | 3 |
Total Red shows the total of all red balls regardless of ball number.
This more involved subquery (for red) produces the exact same result:
(SELECT SUM(cc) FROM
(SELECT DISTINCT count AS cc FROM t1 WHERE color = 'red') AS dd )
AS 'Total Red'
I've added GROUP BY to this subquery to no added effect.
This is as close as I've been able to get.
Many other tries have given a variety of results.
Try combining SUM and IF:
SELECT
ball,
SUM(IF(color = 'blue', count, 0)) AS 'Total Blue'
SUM(IF(color = 'red', count, 0)) AS 'Total Red'
FROM t1
GROUP BY ball
I just want to offer the following, because CASE is standard SQL and IF is not:
select ball,
sum(case when color = 'blue' then `count` else 0 end) as TotalBlue,
sum(case when color = 'red' then `count` else 0 end) as TotalRed
from t
group by ball
order by 1
Also, having "count" as the name of a column is a bad idea, because it is an SQL reserved word.