SQL troubling with multiple count in query - sql

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(!)

Related

Why Oracle OFFSET and LIMIT is not working when using DISTINCT

I need to get clarified the below situation.
I have a city, country table and I need to validate this will some other tables and get the city country results ordered by the country. Here's my query for that
SELECT distinct
c.code as CITY ,
c.country as COUNTRY from location_info li
inner join someTable s on li.loc_id = s.some_id
inner join city c on s.city = c.code
ORDER BY c.country
And this provides the results as
Now when I use OFFSET and LIMIT values in the below query
SELECT distinct
c.code as CITY,
c.country as COUNTRY from location_info li
inner join someTable s on li.loc_id = s.some_id
inner join city c on s.city = c.code
ORDER BY c.country OFFSET 5 ROWS FETCH NEXT 5 ROWS ONLY.
I expect to get ADOR, ADPC, ADSJ, ADVD, ALV as the output.
Why is that and what I am missing here in this query.
When I do the following I get the expected outcome
SELECT CITY, COUNTRY FROM ( SELECT distinct
c.code as CITY,
c.country as COUNTRY from location_info li
inner join someTable s on li.loc_id = s.some_id
inner join city c on s.city = c.code
ORDER BY c.country ) OFFSET 5 ROWS FETCH NEXT 5 ROWS ONLY.
The issue is that the ORDER BY is not stable. What that means is that you have ties in the key values. So, running the query two times might result in different orderings.
This is easily fixed by including more keys in the order by so the order by keys uniquely identify each row:
select distinct c.code as CITY, c.country as COUNTRY
from location_info li join
someTable s
on li.loc_id = s.some_id join
city c
on s.city = c.code
order by c.country, c.code;

GROUP BY with JOIN not giving correct result

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.

Using a subquery with inner join in the from clause?

I'm trying to create a table that with one column containing the number of countries and the next column being the number of official countries. So basically, one row might say there are 32 countries that have 2 official languages, 28 with 3 official languages, etc.
So far I've made a table that counts the number of official languages per each individual country.
select c.name, count(l.language) number_of_languages from world.country c
inner join (select countrycode, language, isofficial from
world.countrylanguage where isofficial='T') l on c.code=l.countrycode group
by c.name order by count(l.language)
Here's a sample of the result:
NAME NUMBER_OF_LANGUAGES
---------------------------------------------------- -------------------
Lesotho 2
Sri Lanka 2
Canada 2
Singapore 3
Belgium 3
Bolivia 3
First, your query can be simplified. It doesn't need to use a subquery:
select c.name, count(cl.language) as number_of_languages
from world.country c inner join
world.countrylanguage cl
on c.code = cl.countrycode
where cl.isofficial = 'T'
group by c.name
order by count(cl.language);
Next, use this as a subquery:
select number_of_languages, count(*)
from (select c.name, count(cl.language) as number_of_languages
from world.country c inner join
world.countrylanguage cl
on c.code = cl.countrycode
where cl.isofficial = 'T'
group by c.name
) cl
group by number_of_languages
order by number_of_languages;

Nested 'Where'?

I have a table named Actor, with only a column for City (CityId). I want to return the number of actors in a particular State (StateId). The catch however is that I have separate tables for City, County, and finally State (City has CountyId, County has StateId). How do I this in a T-SQL query?
I have a solution that involves nested Select statements, something like:
SELECT COUNT(1)
FROM Actor a
WHERE a.CityId IN
(SELECT CityId FROM City WHERE CountyId IN...)
...but is there a more efficient way to do this? Thanks
You can use this query to get your output
----------------------------------------------------------
SELECT COUNT(ActorId)
FROM Actor a
INNER JOIN City c ON a.cityId = c.cityId
INNER JOIN Country con ON c.countryId = con.countryId
INNER JOIN STATE s ON con.stateId = s.stateId
GROUP BY s.stateId
Use JOINS to query your data.
I am using INNER JOIN here.
Assuming that you have CountryId in your City Table, You can do it following way.
In case you don't have countryId in your City Table you have to apply one more INNER JOIN on State Table.
SELECT COUNT(1) FROM Actor a INNER JOIN
City b ON a.CityId = b.CityId
WHERE b.CountryId IN (...)
You can easily put the JOINS across different table that you have and then use the Group By clause to find out the total number of actors from specific state.
I have used the column name on the basis of my wild guess, you can change them with the original name that you have in your database.
SELECT StateId,
Count(ActorId) AS Total
FROM ACTOR
INNER JOIN City ON Actor.CityId = City.CityId
INNER JOIN County ON County.CountyId = City.CountyId
INNER JOIN State ON State.StateId = County.StateId
GROUP BY State.StateId
Assuming the relation names, you can do something like this with joins:
select s.ID, s.Name, count(*)
from Actors a
inner join Cities c on c.ID = a.CityID
inner join County cn on cn.ID = c.CountyID
inner join State s on s.ID = cn.StateID
group by s.ID, s.Name
If you only need the StateId you don't even need to join with states, this will do:
select cn.StateID, count(*)
from Actors a
inner join Cities c on c.ID = a.CityID
inner join County cn on cn.ID = c.CountyID
group by cn.StateID

How to sort by count with postgresql?

I have two tables:
Companies: (id, name, city)
Workers: (id, name)
I would like to get all companies and sort them by numbers of employes.
The result should give:
count | company id | company name | city
------------------------------------------
90 6 foo corp NY
45 9 bar corp LA
0 3 foobar corp HO
I tried:
select
c.*,
count(w.id) as c
from
companies c
left join
workers w
on
c.id = w.company_id
group by
c.id
order by
c desc;
But that's not working as it tells me to group by g.name too :/
Any ideas?
You've aliased the table and column as the same thing, so don't do that. It's not invalid, just tough to follow.
Anyway, include all columns that you're selecting that aren't aggregates in your group by:
select
count(w.id) as mycount,
w.company_id,
c.company_name,
c.city
from
companies c
left join workers w on
c.id=w.company_id
group by
w.company_id,
c.company_name,
c.city
order by mycount desc;
If you don't want the count result to be returned (because of an ORM framework or so), you could apply it directly in the order by clause:
select
c.*
from
companies c
left join
workers w
on
c.id = w.company_id
group by
c.id
order by
count(w.id) desc;
Tested with postgreSQL 11
Try this as a subquery:
SELECT C.*
FROM
(
SELECT C.Id, C.Company_Name, C.City, COUNT(W.Id) AS CNT
FROM Companies C
LEFT JOIN Workers W ON W.Company_Id = C.Id
GROUP BY C.Id, C.Company_Name, C.City
) T
ORDER BY T.CNT