MySQL: SELECT and COUNT in same query - mysql

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

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;

Creating simple select on many-to-many relation

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
);

I need a sql query to view data

I have three table which are cities, states and country. Each table contains its respective columns as shown below:
cities{id,cityname,states_id}
states{id,statename,country_id}
country{id,name}
Table Relations
cities table contains [states_id]
states table contain [country_id]
If I select particular city, I would need to display [cityname], [statename] and [countryname]
Based on what you provided:
SELECT ci.cityname
, st.statename
, cr.countryname
FROM Cities ci
JOIN States st ON ci.states_id = st.states_id
JOIN Country cr ON st.country_id = cr.country_id
SELECT cities.cityname, states.statename, countryname
FROM cities JOIN
states ON cities.states_id = states.id JOIN
country ON states.country_id = country.id
WHERE cities.id=3;
Assuming 3 is the id of the city you are searching for...
SELECT c.cityname, s.statename, cy.name AS countryname
FROM cities c
INNER JOIN states s ON s.id = c.states_id
INNER JOIN country cy ON cy.id = s.country_id
WHERE c.id = 123
"123" is the city id you want to be informed about.

SQL query to get records that match ALL the criteria

I need to write a SQL query to get the patients that have stayed in ALL the hospitals of the city where they live. In one city there may be several hospitals of course.
So for example, if the patient 'xxx' who lives in Washington has been in a hospital, I need to list him only if he's been in all the hospitals of Washington and no less.
This is the structure of the tables:
table patient
patientID
patientCity
table hospital
hospitalCode
hospitalCity
table hospital_stay
hospitalCode
patientID
cityStay
What's the most efficient way to do this for MySQL? Thank you!
Unfortunately, MySQL can't order before grouping, so I had to use subquery to order the result correctly before grouping it.
Have fun :)
SELECT * FROM (
SELECT
p.patientID,
hs.hospitalCode
FROM
patient p
INNER JOIN hospital h ON (p.patientCity = h.hospitalCity)
LEFT JOIN hospital_stay hs ON (p.patientID = hs.patientID AND h.hospitalCode = hs.hospitalCode)
ORDER BY 2
) AS tmp_table
GROUP BY 1
HAVING NOT ISNULL(hospitalCode)
This query should work :
Select p.patientID
, p.patientCity
from patient p
inner join hospital h on h.hospitalCity = p.patientCity
inner join hospital_stay hs on hs.hospitalCode = h.hospitalCode
--where hs.cityStay = 1
group by p.patientID, p.patientCity
having count(*) = (select count(*) from hospital
where hospitalCity = p.patientCity);
Remove the comment if cityStay is kind of a flag that says that the patient went to the hospital.

Select rows from table and additional data form other table if exists

I have a hard time figuring out how to write a query that selects all rows that matches certain conditions from one table and extends the rows with data from another table if there is data that matches another set of conditions.
Table: books
id
school
isbn
name
Table: orders
id
school
department
isbn
quantity
The query I have is:
SELECT orders.*, books.name FROM orders
LEFT JOIN books ON orders.isbn = books.isbn
WHERE orders.school = 1 AND orders.department = 2
AND books.school = 1
Now, the problem is that if a school hasn't added their books, isbn and names into the books table I'd still like to have the orders.* data returned with books.name set to null or something similar. Now I get zero rows instead. Is there a way to do this with one query?
Move
and books.school = 1
from the where clause to the from clause.
left join books on orders.isbn = books.isbn
and books.school = 1
Edit starts here
for raheel who says it doesn't matter. Using the world database that came with the MySQL I downloaded, this query
select c.name, city.name cityname
from country c left join city on c.code = city.countrycode
AND city.name = 'toronto'
order by cityname;
returns 239 rows. This query:
select c.name, city.name cityname
from country c left join city on c.code = city.countrycode
WHERE city.name = 'toronto'
order by cityname;
returns 1 row. I think it matters