Creating simple select on many-to-many relation - mysql

Lets say I have this tables:
country:
country_id,
country_name;
currency:
currency_id,
currency_name;
country_currency:
country_id,
currency_id;
I would like to select and show all countries having two or more currencies. How should my query look like?

Join all the tables with the common columns, then group the result by country_id, and count the number of rows (or currency) per group as shown below.
SELECT A.COUNTRY_ID, COUNT(*) NUMBER_OF_CURRENCY
FROM COUNTRY A
INNER JOIN COUNTRY_CURRENCY B ON A.COUNTRY_ID = B.COUNTRY_ID
INNER JOIN CURRENCY C ON B.CURRENCY_ID=C.CURRENCY_ID
GROUP BY A.COUNTRY_ID
HAVING NUMBER_OF_CURRENCY > 1 ;
A better query would be:
SELECT COUNTRY_NAME
FROM COUNTRY
WHERE COUNTRY_ID IN (
SELECT COUNTRY_ID
FROM COUNTRY_CURRENCY
GROUP BY COUNTRY_ID
HAVING COUNT(*) > 1
);

Related

How to extract top populate city from a SQL query

I have a set of tables in a SQL database :
states={id, name} :
id
name.
1
PACA
2
Ile de France
counties={id, name, state_id},
id
name
state_id
1
Paris.
2
2
Bouches du Rhône
1
3
Var
1
cities={id, name, population, county_id}
id
name
population
county_id
1
Paris
2000000
1
2
Marseille
 1900000
2
3
Toulon
952000
2
4
Hyères
52575
2
And would be able to extract the most populate city by counties, i.e :
city_name
most_populated
county_name
Paris.
2000000.
Paris.
Marseille
1900000.
Bouches.
Try to execute this query, without success :
SELECT c.id cid, c.name, ci.name,
(SELECT sci.population FROM counties sc JOIN cities sci
ON sc.id = sci.county_id
WHERE sc.id = cid
ORDER BY sci.population DESC
LIMIT 1) AS city_most_populated
FROM counties c JOIN cities ci ON c.id = ci.county_id
GROUP BY c.id;
The result is not what i expected, and don't know how to acheive this kind of query.
Thx for help
Fro MySQL 5.x (which doesn't have ROW_NUMBER()), you can move your correlated sub-query in to the JOIN.
Find the most populated city in the correlated sub-query
Join on only that one city
Note: There is ambiguity as to what you want to happen if two cities are tied for the most populated city in a county. The query below picks the most populated city, per county, then if there are ties for most populated it picks One of those arbitrarily, based on the id.
SELECT
c.id cid,
c.name,
ci.name,
ci.population
FROM
counties c
JOIN
cities ci
ON ci.id = (
SELECT id
FROM cities
WHERE county_id = c.id -- This is what makes it "correlated", it's similar to joining the query to the counties table
ORDER BY population DESC, id DESC
LIMIT 1
)
In this query there are two references to the cities table. This enables the correlated sub-query to process all cities per county then return one id, allowing the join on to the other cities reference to be on to exactly one row. (Having two references to the same table also requires use of aliases.)
Demo: https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=73e93e61f88efee11e02f1e832c8510b
EDIT:
I had ON c.id = but that was a typo.
It is now corrected to ON ci.id =
If you're using MySQL 8+ then use ROW_NUMBER here:
WITH cte AS (
SELECT c.id AS city_name, c.population, cn.name AS county_name,
ROW_NUMBER() OVER (PARTITION BY cn.id ORDER BY c.population DESC) rn
FROM cities c
INNER JOIN counties cn ON cn.id = c.county_id
)
SELECT city_name, population, county_name
FROM cte
WHERE rn = 1;
You would use row_number():
SELECT cc.*
FROM (SELECT c.id as cid, c.name as country_name, ci.name as city_name,
ROW_NUMBER() OVER (PARTITION BY c.id ORDER BY ci.population DESC) as seqnum
FROM counties c JOIN
cities ci
ON c.id = ci.county_id
) cc
WHERE seqnum = 1;

SQL: Selecting all tuples which contain a certain value in a column after using count

I have the following table called Stores:
Name | Category | Industry
ABC appliances retail
XYZ banking finance
NZE clothing retail
JKI tutoring education
I would like to output all the Names that are the only one in their Industry (e.g. XYZ and JKI are the only Names in their Industry).
I have the following query:
select s.Name, s.Industry, a.Number
from Stores s
inner join (
select Industry, count(*) as Number
from Stores group by Industry
) a
on s.Industry = a.Industry;
I get an output table which has an attribute called Number which gives the total number of times each Industry appears in the table Stores. How can I select all the tuples which have the value of 1 in the Number column after using the inner join?
use where condition
select s.Name, s.Industry, a.Number
from Stores s
inner join (
select Industry, count(*) as Number
from Stores group by Industry
) a
on s.Industry = a.Industry where a.Number=1
use corelated subquery
select s.* from stores s
where exists ( select 1 from Stores s1 where s.Industry=s1.Industry
having count(*)=1)
You can use EXISTS :
SELECT s.*
FROM Stores s
WHERE EXISTS (SELECT 1 FROM Stores s1 WHERE s1.Industry = s.Industry AND s1.Name <> s.Name);
I would just use aggregation:
select industry, max(name) as name
from stores
group by industry
having count(*) = 1;
If there is only one name, then max(name) is the one.
If names can be repeated in the table, then:
having min(name) = max(name)

MySQL subquery with two tables count and group by

I have database of doctors and hospital joined by hospitaldoctor table.
I have to List town, amount of hospitals in each town, but only hospitals which have more than 5 doctors.
SELECT hospital.town, count(town)
FROM hospital
WHERE hospital.id = (
SELECT count(hospital_id)
FROM hospital_doctor GROUP BY hospital_id
HAVING count(hospital_id)>5 )
GROUP BY town
this is my query but MySQL returns me that subquery returns more than 1 row.
HOSPITAL
HOSPITAL DOCTOR
How i should write this query?
You can do what you want with basically the same structure:
Select h.town, count(*)
from hospital h
where h.id in (select hd.hospital_id
from hospital_doctor hd
group by hd.hospital_id
having count(*) > 5
)
group by h.town ;
Note the following:
You want to use in not =, because the subquery could return more than one row.
The subquery should be returning the hospital id not the count.
Use table aliases and qualified column names whenever a table refers to more than one table.
SELECT h.town, count(h.town)
FROM
(
SELECT hospital_id
FROM hospital_doctor GROUP BY hospital_id
HAVING count(doctor_id)>5
) s1
left outer join hospital h on (s1.hospital_id=h.id)
GROUP BY h.town
Select hospital.town, count(town)
from hospital
where
hospital.id in (
select hospital_id
from hospital_doctor
group by hospital_id
having count(hospital_id)>5
)
group by town

ERROR is "group function is nested too deeply"?

tried to display the name of the department that has the least student count.
Try something like this:
SELECT TOP 1 department_name, count(*) AS number_of_students
FROM department natural join student
GROUP BY department_name
ORDER BY number_of_students
It will give you the list of departments ordered by the number of students. By selecting only the first row via TOP 1 you will only get the department with the least number of students.
Is it like this way?
SELECT
T1.department_name, COUNT(T2.department_id) totalCount
FROM department T1
LEFT JOIN student T2
ON T1.department_id = T2.department_id
GROUP BY T2.department_id
HAVING COUNT(T2.department_id) =
(
SELECT
COUNT(T2.department_id) totalCount
FROM department T1
LEFT JOIN student T2
ON T1.department_id = T2.department_id
GROUP BY T2.department_id
ORDER BY totalCount ASC
LIMIT 1
)
SQLFIDDLE DEMO

MySQL: SELECT and COUNT in same query

I have these two tables:
CITY TABLE
CLUB TABLE
What I'm trying to do, is to select with the same query all cities that contain published clubs (published field set to 1) and the total of clubs published in that city.
At the moment, I am doing it with two steps, but I would like to improve performance by merging these in just one query.
SELECT c.id, c.name, c.slug
FROM city c, club cl
WHERE c.id = cl.city_id
AND ( SELECT COUNT(*)
FROM club cl, city c
WHERE cl.city_id = c.id AND cl.published = 1) > 0
GROUP BY c.id
After this, I'm doing a query for each city just to get the COUNT.
Something like this:-
SELECT city.id, city.name, city.slug, COUNT(club.id) AS club_count
FROM city
INNER JOIN club
ON city.id = club.city_id
WHERE club.published = 1
GROUP BY city.id, city.name, city.slug
HAVING club_count > 0