SQL: What country has the most cities? - mysql

Hello I started using MySQL and I seem to be having trouble trying to nest formulas. I'm working on a problem and the question is, What country has the most cities?
I have two tables:
CITY:
city
city_id
country_id
COUNTRY:
country
country_id
I am able to join the two tables together to get the cities to match with the countries but after that I don't know how to count to the country that has the most cities.
My current code is:
SELECT city.city, country.country
FROM city, country
WHERE city.country_id = country.country_id
From there I don't know how to add a count function without it coming back as as error. I dont fully understand the basics of nesting.
Thank you, any help is appreciated.

You do not need to do nesting necessarily. To simply know, which country has most number of cities, just use group by:
select country_id, count(1)
from city
group by country_id
This will give you the number of cities in each country. Then you could use a CTE to get the country with the largest number of cities.

You need to GROUP BY if you want to use aggregate functions.
Given the fact that you're very new to this I think you'll get a lot more out of this if you spend a few minutes reading up on some documentation. Don't worry, this is easy stuff so you'll understand this in no time. Please have a look at the following basic info (MySQL GROUP BY basic info) regarding the use of GROUP BY in MySQL. Your questions are answered in the topic regarding 'MySQL GROUP BY with aggregate functions'.
Basic group by:
SELECT
status, COUNT(*)
FROM
orders
GROUP BY status;
Group by using a join:
SELECT
status, SUM(quantityOrdered * priceEach) AS amount
FROM
orders
INNER JOIN
orderdetails USING (orderNumber)
GROUP BY status;

SELECT x.country
FROM country x
JOIN city y
ON y.country_id = x.country_id
GROUP
BY x.country
ORDER
BY COUNT(*) DESC LIMIT 1;
On the (fantastically unlikely) chance that the most civilised countries have equal numbers of cities, you would have to amend this a little.

What makes this difficult is possible ties, i.e. two or more countries sharing the maximum number of cities. As of MySQL 8 you can use window functions to help you with this. Here I compare the country counts and their maximum and then pick the rows were the two match.
select *
from country
where (country_id, true) in -- true means it is a maximum city country
(
select country_id, count(*) = max(count(*)) over()
from city
group by country_id
);

Sorry it was my first post, my code looks terrible.
following my code again.
select
country.country_id,
count(city.city_id)
from
country
inner join
city
on
city.country_id=country.country_id
group by
city.country_id
having
count(city.city_id) =
(SELECT
max(count(city.city_id))
FROM
city
GROUP BY
city.city_id);
Best regards,
Jens

Try the following code:
**select
country.country_id,
count(city.city_id)
from
country
inner join
city
on
city.country_id=country.country_id
group by
city.country_id
having
count(city.city_id) =
(SELECT
max(count(city.city_id))
FROM
city
GROUP BY
city.city_id);**
You need to group by country_id to make sure all cities that are connected to one country_id can be counted.
Where is a good approach, however it does not work together with "group by" as it will be accounted before the "group by" command.
The way you joined your data from different tables is not a very proper yet working way. I suggest to use the inner join in this case to make the command more obvious/better readable.
Count() is used to count the number of cities that accumulate on one country
max() is used to get the country with the most cities (highest count()).

SELECT country_id, count(1)
FROM city
GROUP BY country_id
ORDER BY count(1) desc;

Try following Code -
SELECT *,
(SELECT COUNT(*) FROM cities WHERE cities.country_id=C.country_id) as cities_count
FROM country C
ORDER BY cities_count DESC
LIMIT 0,1
Also is joining the two tables necessary? In your query, you said you need to find What country has the most cities?
Above query will only return one country with max cities.

You can find the country like this:
SELECT MAX(c.id) FROM (SELECT COUNT(id) AS id
FROM city group by country_id) c

Related

I can't figure out which SQL command to run for this task. I am using the sakila database for practice

I need to provide a list of the “high interest” countries. A “high interest” country is defined as a country in which we have 20 or more customers. For each “high interest” country, list the country’s name and the number of customers in that “High Interest” country. I need to order the list by the number of customers in descending order.
Any ideas on how to get these results from the sakila database? Here's my SQL that I've written so far:
SELECT DISTINCT country.country, COUNT(customer.customer_id) AS customer_count
FROM customer
INNER JOIN address ON customer.address_id=address.address_id
INNER JOIN city ON address.city_id=city.city_id
INNER JOIN country ON city.country_id=country.country_id
HAVING COUNT(customer_id) >= 20
ORDER BY COUNT(customer_id) DESC;
I don't know the sakila database, but it seems you only miss the group by statement. GROUP BY country.country just before the having-clause. I think you only got no errors because mysql is very 'tolerant' with columns not grouped or aggregated.
This problem was solved by Turo's comment. Adding the GROUP BY statement displayed the results I needed.

question to get the correct code for a specific query from a database

i have a problem with the code to get an specific information from a database.
What i want is the number of cities repeated in each CountryCode (country).
what is get until this moment is the number of cities reapeated in each group of city.Name (groups with the same value of city.Name),
SELECT count(*) as numberOfCitiesRepeated,city.CountryCode from city
group by city.Name
having count(*) >1
order by countryCode
and thats good beacuse i only have to count the number of values group by CountryCode (country) and i will solve the problem, but i tried:
COUNT(SELECT count(*) as numberOfCitiesRepeated,city.CountryCode from city
group by city.Name
having count(*) >1
order by countryCode) from city group by city.CountryCode
and it didnt work, it doesnt compile.
thats the mysql db im using:
and this is what the first query return me:
I solved my problem with the help of Eric and a mysql concept called VIEWS.
I could obtain the number of cities repeated of a determined country using 2 queries. In this example i get the number of cities repeated of china which its countryCode is CHN.
With this query you create a view which get the cities repeated from a country and the countrycode of the country which it belong.
CREATE VIEW citiesRepeatedInCountries as
SELECT city.Name, city.CountryCode FROM city
GROUP BY city.Name, city.CountryCode
HAVING count(*) > 1
order by countryCode
An with this query you count the quantity of register which its countryCode is CHN.
select count(*) as numOfCitiesRepeatedInChina from world.citiesRepeatedInCountries
where world.citiesRepeatedInCountries.CountryCode='CHN'
:)

Mysql - How can I subtract the number of rows returned by 2 queries

in trying to learn MySQL, I've been solving the problems from Hackerrank. I've got stuck at this problem, which asks:
"[...]find the difference between the total number of CITY entries in the table and the number of distinct CITY entries in the table."
The idea is to output a single answer N' - N.
The schema looks like this:
To this effect, the query I've tried is:
select count(s2.c2) - count(s1.c1)
from (select city as c1 from station group by city) as s1,
(select city as c2 from station) as s2;
I've also tried many other variants, but none of them give me the right answer. Where am I going wrong? I've also looked up other questions on SO but they do not return a single number.
Thank you.
Just use count(distinct), and no need to use self-join, try following:
select
count(city) - count(distinct city)
from station
There are different ways of doing this. To use your direction:
select total_cities - count(distinct_cities)
from (select count(*) as distinct_cities from station group by city) as s1,
(select count(*) as total_cities from station) as s2
GROUP BY total_cities;
So first counting the distinct_cities to have just a unique list, you could also use:
SELECT DISTINCT city AS distinct_cities FROM station
And then counting the total number of distinct cities by counting these again in the outer query. Hope this helps you to think of more (shorter) ways of writing this.

mysql group by multiple

I'm not sure if this is specifically a group by question, as I've tried grouping this by multiple columns. Basic problem is a table like this:
I would like to get the sum of the order total_price for different countries, but grouped by the order_id. So for France the sum of total_price should be 8000 as two of the rows are for the same order. My sql is clearly wrong as I am not getting this.
SELECT sum(total_price) as total_price_per_country
FROM cars
WHERE (country IN ('France'))
group by order_id, country;
Nope, GROUP BY won't quite get you that. If you GROUP BY country you get one row per country.
There's no way to do this without a second query, so it'd have to be something like this:
SELECT *, (SELECT SUM(total_price) FROM cars AS c2 WHERE c2.country = cars.country) AS total_price_per_country
FROM cars
(An INNER JOIN to a second copy of the table would work too.)
select sum(total_price) from cars where country = 'France' group by order_id
Try above query

MySQL error 1242: Subquery returns more than 1 row

I'm working on some SQL homework, and I've come to a dead-end on this one question and I'm hoping someone can point out what exactly I'm doing wrong here.
SELECT Name,
(SELECT Name
FROM City
WHERE City.CountryCode = Country.Code) AS 'city',
(SELECT Population
FROM City
WHERE City.CountryCode = Country.Code) AS 'city_population'
FROM Country
WHERE Region IN ('Western Europe')
HAVING city_population > (SUM(Population) / COUNT(city))
ORDER BY Name, city;
What I'm trying to do here is retrieve from a database of global statistics a list of cities (from the City table) matched with their Country from that table, in which the country is in the region of Western Europe and the population of the city is greater than the average population of cities for its country, ordered by country and city name. The CountryCode and Code are the keys for the tables.
Can anyone tell me where I'm going wrong? I'm guessing MySQL is unhappy because my subqueries are returning more rows than the selector for country names does, but that's exactly what I want to do. I want multiple rows for a country value, one row for each city that meets the search criteria of having greater than average populations. The assignment also specifically forbids me from using joins to solve this problem.
A join should do it. You can join city on country code, and filter out cities that have a lower than average population
select
co.Name as CountryName,
ci.Name as CityName,
ci.Population as CityPopulation
from
Country co
inner join City ci
on ci.CountryCode = co.CountryCode
where
co.Region in ('Western Europe')
and ci.Population >
(select sum(ca.Population) / count(*) from City ca
where ca.CountryCode = co.CountryCode)
Additions:
Since you are not allowed to use joins, you could solve it in a couple of ways.
1) You can alter your query a little bit, but it won't return rows for each city. Instead it will return the list of cities as a single field. This is only a slight modification of your query. Note the GROUP_CONCAT function, which works like SUM only it concats the values instead of summing them. Also note the added ORDER BY clause in the subselects, so you can make sure The nth Population matches the nth City name.
SELECT Name,
(SELECT GROUP_CONCAT(Name)
FROM City
WHERE City.CountryCode = Country.Code
ORDER BY City.Name) AS 'city',
(SELECT GROUP_CONCAT(Population)
FROM City
WHERE City.CountryCode = Country.Code
ORDER BY City.Name) AS 'city_population'
FROM Country
WHERE Region IN ('Western Europe')
HAVING city_population > (SUM(Population) / COUNT(city))
ORDER BY Name, city;
2) You can alter by query a little bit. Remove the join on Country, and instead use some subselects in the filter and in the select. The latter is only needed if you need country name at all. If country code is enough, you can select that from City.
select
(select County.Name
from Country
where County.CountyCode = ci.CountryCode) as CountryName,
ci.CountryCode,
ci.Name as CityName,
ci.Population
from
City ci
where
-- Select only cities in these countries.
ci.CountryCode in
( select co.CountryCode
from Country co
where co.Region in ('Western Europe'))
-- Select only cities of above avarage population.
-- This is the same subselect that existed in the join before,
-- except it matches on CountryCode of the other 'instance' of
-- of the City table. Note, you will _need_ to use aliases (ca/ci)
-- here to make it work.
and ci.Population >
( select sum(ca.Population) / count(*)
from City ca
where ca.CountryCode = ci.CountryCode)
A subquery in the the select part of the statement only expects one value returned from the query. Remember the commas that separate the values in your select statement represent columns and each column expects one value. In order to get a list of values returned in a subquery (as if it were another table) and use it in the outer query you would have to put the subqueries in the from part of your Query. Note: this may not be a proper code for your results. I was just addressing the issue of the MySQL error 1242.
SELECT Name
FROM Country, (SELECT Name
FROM City
WHERE City.CountryCode = Country.Code) AS 'city',
(SELECT Population
FROM City
WHERE City.CountryCode = Country.Code) AS 'city_population'
WHERE Region IN ('Western Europe')
HAVING city_population > (SUM(Population) / COUNT(city))
ORDER BY Name, city;