I am not quite sure with the tables below to write a query that returns countries that have communities. The CommunityLocation bridge table is where I can look for companies and their locations but not quite sure how to really mold this query.
Community
community_id
Location
location_id
country_id
Country
country_id
CommunityLocation
community_id
location_id
So I just need a list of country IDs that have communities.
I think this is what you need:
select distinct
c.country_id
from
countires c
join Location l
on c.country_id = l.country_id
join CommunityLocation cl
on cl.location_id = l.location_id
I would recommend exists:
select c.country_id
from countries c
where exists (select 1
from Location l join
CommunityLocation cl
on cl.location_id = l.location_id
where c.country_id = l.country_id
);
This avoids extra processing for removing duplicates -- and that is usually a performance gain.
Related
I am trying to use a Set operator to show country names(Table A col.) without a city(Table B col.) and cities(B) without a country(A). I have also tried to write this query using LEFT JOINS, which I show below and I included Table C(Regions) because I am not sure whether to use that primary key in a LEFT JOIN.
Table A (Countries):
Column_name | Column_id
|
COUNTRY_ID | 1
COUNTRY_NAME | 2
REGION_ID | 3
Table B (Locations):
Column_name | Column_id
|
LOCATION_ID | 1
CITY | 4
COUNTRY_ID | 6
Table C(Regions):
Column_name | Column_id
|
REGION_ID | 1
I have tried the following:
SELECT c.country_name, l.city
FROM Countries c
LEFT JOIN Locations l ON c.country_id = l.country_id
UNION
SELECT c2.country_name, l2.city
FROM Countries c2
LEFT JOIN Locations l2 ON c2.country_id = l2.country_id;
The SQL statement above returned all Table A values, and Table A values that do not contain Table B values (Countries that do not have Cities).
I also tried this statement below and got the exact same result:
SELECT c.country_name, l.city
FROM Countries c
LEFT JOIN Locations l ON c.country_id = l.country_id
LEFT JOIN Regions r ON r.region_id = c.region_id;
The one thing it is missing is Table A values not found in Table B (Countries not found in Cities.)
There are a lot of options to get your desired result. One way is to use LEFT JOIN to get the countries without city and RIGHT JOIN to get the cities without country:
SELECT c.country_name, l.city
FROM countries c
LEFT JOIN locations l ON c.country_id = l.country_id
WHERE l.city IS NULL
UNION ALL
SELECT c.country_name, l.city
FROM countries c
RIGHT JOIN locations l ON c.country_id = l.country_id
WHERE c.country_name IS NULL;
Another possibility is to use two LEFT JOIN, but starting from the opposite table, like this:
SELECT c.country_name, l.city
FROM countries c
LEFT JOIN locations l ON c.country_id = l.country_id
WHERE l.city IS NULL
UNION ALL
SELECT c.country_name, l.city
FROM locations l
LEFT JOIN countries c ON c.country_id = l.country_id
WHERE c.country_name IS NULL;
If you don't like using JOIN at all, you can do this using NOT IN:
SELECT c.country_name, NULL city
FROM countries c
WHERE country_id NOT IN (SELECT country_id FROM locations)
UNION ALL
SELECT NULL country_name, l.city
FROM locations l
WHERE country_id NOT IN (SELECT country_id FROM countries);
Or if you prefer NOT EXISTS, this will work, too:
SELECT c.country_name, NULL city
FROM countries c
WHERE NOT EXISTS (SELECT 1 FROM locations WHERE country_id = c.country_id)
UNION ALL
SELECT NULL country_name, l.city
FROM locations l
WHERE NOT EXISTS (SELECT 1 FROM countries WHERE country_id = l.country_id);
I created an example that shows all these queries will produce the identic outcome: db<>fiddle
Add ORDER BY c.country_name and ORDER BY l.city to the queries in case you want the result set to be sorted by them.
A last, but important note: As you see, I used UNION ALL instead of UNION because I don't see a reason why to use UNION in your use case. UNION ALL is much faster, so I recommend to use that unless there is a really convincing reason to do not use it. The only advantage of UNION is that it does not show duplicate rows, but I think they are very unlikely in your situation, so it should not be required.
The simplest illustration of using a set operator to find countries without cities would be:
select country_id from countries
minus
select country_id from locations
COUNTRY_ID
----------
1
4
As you need the country name, you just need to look it up:
select country_name from countries
minus
select c.country_name from locations l
join countries c on c.country_id = l.country_id;
COUNTRY_NAME
-----------------
England
Italy
Cities without a country (or with an invalid country code) is simpler as a left join and filter:
select l.city, l.country_id
from locations l
left join countries c on c.country_id = l.country_id
where c.country_id is null
CITY
-----------------
Berlin
Tokyo
If the requirement really is to do this using set operators, you would (conceptually) look for cities whose country_id is in the set of (location countries minus city countries):
select l.location_id, l.city, l.country_id
from locations l
where l.country_id in
( select country_id from locations
minus
select country_id from countries )
However this wouldn't give you locations whose country_id was null.
I'm writing query that returns number of people working in country. User have to input COUNTRY_ID which he is interested in.
I wrote down query that works fine, but only with hardcoded COUNTRY_ID.
SELECT COUNT(e.EMPLOYEE_ID)
FROM EMPLOYEES e
JOIN DEPARTMENTS d ON e.DEPARTMENT_ID = d.DEPARTMENT_ID
JOIN LOCATIONS l ON d.LOCATION_ID = l.LOCATION_ID
JOIN COUNTRIES c ON l.COUNTRY_ID = c.COUNTRY_ID
WHERE c.COUNTRY_ID = 'US';
With hardcoded COUNTRY_ID query returns 68 rows, with user input query returns 0 rows.
c.COUNTRY_ID = '&c.COUNTRY_ID'
Maybe I'm using this function wrongly, I would be glad for solution. Thanks.
How can I find the number of persons from each country
Person table
country_id, fName, lName
Countries table
country_id, country_name
I can find the number of persons from each country with their country IDs, using the below SQL statement
select
p.country_id, COUNT(p.country_id) as [Count]
from
persons p
GROUP BY
p.country_id
But what if I want to fetch country_name instead of country_id?
I tried this so far but it does not work as expected so I am missing something here.
select
c.country_name, COUNT(p.country_id) as [Count]
from
persons p INNER JOIN countries c ON p.country_id = c.country_id
GROUP BY
p.country_id
SQL Server 2000
GROUP BY the columns in the SELECT:
SELECT c.country_name, COUNT(p.country_id) as [Count]
FROM persons p INNER JOIN
countries c
ON p.country_id = c.country_id
GROUP BY c.country_name;
Notes:
Under some circumstances, you would want to include both the id and the name in the GROUP BY -- this would happen if two countries had the same name.
You can use COUNT(*) instead of COUNT(p.country_id). There is no problem counting rows instead of NULL-values.
If you wanted all countries, even those without people, then you would use an outer JOIN:
SELECT c.country_name, COUNT(p.country_id) as [Count]
FROM countries c LEFT JOIN
persons p
ON p.country_id = c.country_id
GROUP BY c.country_name;
You need to mention the column_name which is mentioned in select .
select
c.country_name, COUNT(p.country_id) as [Count]
from
persons p INNER JOIN countries c ON p.country_id = c.country_id
GROUP BY
c.country_name
You could use group by c.country_name .. the column you have in select and you use for refer the group by
select c.country_name, COUNT(p.country_id) as [Count]
from persons p INNER JOIN countries c ON p.country_id = c.country_id
GROUP BY c.country_name
The SQL statement is correct. There was some data corruption in the database due to which the results were not returned correctly.
I have a Set of tables
Hotels
Countries
Regions
Cities
Hotel_Types
and a many to many relations table named Mappings which contains all the relations/mappings which contains info like
id, hotel_id, reference_type, reference_id, ...
where reference_type can be a Country, Region, City, Hotel_Type etc
and reference_id is the id of said entity like country_id or city_id etc.
I need to create a list of all possible combinations of
Country_Name+Hotel_Type_Name
Region_Name+Hotel_Type_Name
City_Name+Hotel_Type_Name
Where the hotels exist. Any help how may I access the names from different tables and how to combine them
I am implying few things here but you could do inner joins in this way:
select name, hotel_type_name
from (select c.country_name as name, h.hotel_type_name Mappings m inner join Countries c on m.reference_type='Country' and m.reference_id=c.country_id inner join hotel_Types h on m.reference_type='Hotel_type' and m.reference_id=h.hotel_type_id) union all
(select c.region_name as name, h.hotel_type_name Mappings m inner join Regions r on m.reference_type='Region' and m.reference_id=r.region_id inner join Hotel_Types h on m.reference_type='Hotel_type' and m.reference_id=h.hotel_type_id) union all
(select c.city_name as name, h.hotel_type_name Mappings m inner join Cities ci on m.reference_type='City' and m.reference_id=ci.city_id inner join Hotel_Types h on m.reference_type='Hotel_type' and m.reference_id=h.hotel_type_id)
This will list unique combinations of Country_Name+Hotel_Type_Name
--link hotels to hotel_type
with Hotel_Hotel_Types as (
select h.hotel_id
,ht.reference_id as hotel_types_id
from Hotels as h
inner join Mappings ht on ht.reference_type = 'Hotel_Type' and h.hotel_id = ht.hotel_id
)
--link hotels to Country_Name
,Hotel_Country_Name as (
select h.hotel_id
,c.reference_id as countries_id
from Hotels as h
inner join Mappings c on c.reference_type = 'Country' and h.hotel_id = c.hotel_id
)
select distinct ht.*, c.*
from Hotel_Hotel_Types hht
inner join Hotel_Types ht on ht.hotel_types_id = hht.hotel_types_id
inner join Hotel_Country_Name hc on hc.hotel_id = hht.hotel_id
inner join Countries c on с.countries_id = hc.countries_id
Region_Name+Hotel_Type_Name and City_Name+Hotel_Type_Name can be queried using similar sqls.
I already provide sql fiddle with schema and sample data.
http://sqlfiddle.com/#!2/e9d22/7/0
If I would like to know how many province and how many cities in Thailand.
Country Name | No. Provinces | No. Cities
Thailand | 77 | 1234
I guess that it need to use multiple COUNT(*) but I dont know how to use it.
Anybody know please suggest solution?
You need to use GROUP BY and COUNT:
SELECT c.name, count(distinct p.id) provincecoutn, count(distinct city.id) citycount
FROM country c
LEFT JOIN province p on c.id = p.country_id
LEFT JOIN City on p.id = city.province_id
GROUP BY c.name
Good luck.
Try this:
SELECT
C.Name, COUNT(DISTINCT P.Id) NoProvance, COUNT(CC.Id) NoCities
FROM country C
JOIN province P
ON C.Id = P.COUNTRY_ID
JOIN city CC
ON P.Id = CC.province_id
WHERE C.Name = 'Thailand'
GROUP BY C.Name
SQL FIDDLE DEMO
It's probably faster to count cities per province before joining to province:
SELECT c.name AS "Country Name"
,count(p.id) AS "No. Provinces"
,sum(ci.city_ct) AS "No. Cities"
FROM country c
LEFT JOIN province p ON p.country_id = c.id
LEFT JOIN (
SELECT province_id, count(*) AS city_ct FROM city GROUP BY 1
) ci ON ci.province_id = p.id
GROUP BY 1
-> sqlfiddle for PostgreSQL(!)