AVG COUNT Query - sql

I am trying to do a query but I donĀ“t know how to do it.
These are the tables:
Table Hospital Table Doctor Table Work
Hid Country ic Hid ic
1 England 1 1 1
2 Spain 2 1 2
3 France 3 1 3
4 England 4 2 4
5 China 5 4 5
Result that I want:
Country Average of Doctors Working on that Hospitals of that Country
England 2 (the doctor with ic 1, 2, 3, and 4/number of hid)
Spain 1
France 0
China 0
I tried:
SELECT DISTINCT H.country, AVG(D.ic)
FROM Hospital H, Doctor D
WHERE H.hid IN
( SELECT W.hid
FROM Work W
WHERE W.ic IN
( SELECT COUNT(D.ic)
FROM D Doctor ....
)
)
GROUP BY(H.country);

Try this
select H.Country, count(W.ic) / count(distinct H.hid) as [Average]
from Hospital as H
left outer join Work as W on W.Hid = H.Hid
group by H.Country
SQL FIDDLE

First get the number of doctors for each hospital, then get the average over that:
select country, avg(docs) as avg_doctors_working
from (
select country, h.hid, count(*) as docs,
from hospital h
left join work w on w.hid = h.hid
group by 1, 2) x
group by 1;

Related

PostreSQL filter results by subset of a joined table and group them

I have table of people, another table of cars and a third table to join them since they have a many to many relationship. I want to select people who own a certain set of cars and group them by a region property on the person. So for example I would want to find all American's who own a Honda and a Nissan.
Example:
people table
id name region
1 Jon America
2 Jane Europe
3 Mike America
cars table
id make
1 Honda
2 Toyota
3 Nissan
people_cars table
person_id car_id
1 1
1 3
2 2
3 1
Desired result:
region own_honda_and_nissan
America 1
Europe 0
An idea for a SQL expression I have is:
SELECT
people.region,
CASE WHEN SUM(CASE WHEN cars.name IN ('Honda', 'Nissan') THEN 1 ELSE 0 END) = 2 THEN 1 ELSE 0 AS own_honda_and_nissan
FROM people
JOIN people_cars ON people_cars.person_id = people.id
JOIN cars ON people_cars.car_id = cars.id
GROUP BY people.region
HAVING
SUM(CASE WHEN cars.name IN ('Honda', 'Nissan') THEN 1 ELSE 0 END) = 2
ORDER BY own_honda_and_nissan DESC
This works if you group by people.id but once they get grouped by region it no longer works.
Use two levels of aggregation:
SELECT p.pregion, COUNT(*) as own_honda_and_nissan
FROM (SELECT pid, p.region,
FROM people p JOIN
people_cars pc
ON pc.person_id = p.id JOIN
cars c
ON pc.car_id = c.id
WHERE c.name IN ('Honda', 'Nissan')
GROUP BY p.id, p.region
HAVING COUNT(DISTINCT c.name) = 2
) p
GROUP BY p.region
ORDER BY own_honda_and_nissan DESC

SQL: Find country name of the team having the most players who have never scored a goal

I have the following tables:
create table Players (
id integer,
name varchar(50) not null,
birthday date,
memberOf integer not null,
position varchar(20).
primary key (id),
foreign key (memberOf) references Teams(id)
);
create table Goals (
id integer,
scoredIn integer not null,
scoredBy integer not null,
timeScored integer not null,
rating varchar(20),
primary key (id),
foreign key (scoredIn) references Matches(id),
foreign key (scoredBy) references Players(id)
);
create table Teams (
id integer,
country varchar(50) not null,
primary key (id)
);
I have the following data in the above tables:
PLAYERS:
id | name | birthday | memberof | position
7 Mina 1997-01-20 1 Captain
9 John 1997-09-01 1 Quarterback
2 Minnie 1995-10-13 3 Goalkeeper
13 Lisa 1997-03-27 4 Captain
12 Rina 1995-01-03 2 Fullback
11 Jasper 2002-09-22 1 Halfback
17 Rose 1997-02-11 1 Goalkeeper
22 Parvin 1993-03-09 3 Goalkeeper
25 Nasom 1996-12-29 3 Fullback
GOALS:
id | scoredin | scoredby | timescored | rating
1 10 7 60 amazing
2 10 7 30 okay
3 10 7 90 amazing
4 20 9 119 nice
5 20 9 80 amazing
6 20 9 75 amazing
7 30 2 30 nice
8 30 2 90 amazing
9 40 13 110 amazing
TEAMS:
id | country
1 Australia
2 Malaysia
3 Japan
4 Thailand
I am trying to output the country name of the team which has the most players who have never scored a goal. The output should be:
Country | Players
Australia 2
Japan 2
I have the following view, which gives the count of players who have never scored a goal for each country:
create or replace view zerogoals as
select t.country, count(*)
from (
select distinct p.id, p.name, p.memberof, g.scoredby
from players p
full outer join goals g
on p.id = g.scoredby where scoredby is null
) s
inner join teams t on t.id = s.memberof group by t.country;
The above query gives me the following output:
country | count
Australia 2
Japan 2
Malaysia 1
I tried using the max function to get the desired output:
select country, max(count)
from zerogoals
group by country;
However I get the following output:
country | max
Australia 2
Japan 2
Malaysia 1
I am not sure how to get the tuples in the view zerogoals with the maximum value for the attribute count. Any insights are appreciated.
You can use a CTE:
with cte as (
select
t.id, t.country, count(*) players
from teams t inner join (
select * from players
where id not in (select scoredby from goals)
) p on p.memberOf = t.id
group by t.id, t.country
)
select country, players
from cte
where players = (select max(players) from cte)
order by country
See the demo.
Results:
country | players
Australia | 2
Japan | 2
You could try using a inner join between the player, team and the list of not in goals ordered by count and limit to 1
select t.name , count(*)
from player p
INNER JOIN team t ON t.id = p.memberof
inner join (
select p.id
from PLAYERS p
where p.id NOT IN (
select scoredby
from GOALS
) ) t1 on t1.id = p.id
group by t.name
order by count(*) desc
limit 1
if you want all the max then
select t.name , count(*)
from player p
INNER JOIN team t ON t.id = p.memberof
inner join (
select p.id
from PLAYERS p
where p.id NOT IN (
select scoredby
from GOALS
) t1 on t1.id = p.id
group by t.name
having count(*) = (
select t.name , count(*)
from player p
INNER JOIN team t ON t.id = p.memberof
inner join (
select p.id
from PLAYERS p
where p.id NOT IN (
select scoredby
from GOALS
) t1 on t1.id = p.id
group by t.name
order by count(*)
limit 1
)
To get the number of players per country with no goal, you can use:
select t.name, count(*) as num_players_no_goal
from team.t join
player p
on t.id = p.memberof
where not exists (select 1
from goals g
where g.scoredby = p.id
)
group by t.name;
To limit this to just the maximum number, use window functions:
select name, num_players_no_goal
from (select t.name, count(*) as num_players_no_goal,
rank() over (order by count(*) desc) as seqnum
from team.t join
player p
on t.id = p.memberof
where not exists (select 1
from goals g
where g.scoredby = p.id
)
group by t.name
) t
where seqnum = 1;
One slight caveat is that this returns no teams if all players on all teams have scored goals. It is easily modified for that situation, but I'm guessing that you would rather return zero teams than all teams if that were the case.

How to count how many hits for a given id in the second table

I have 3 tables like "brands" and "whisky" and "country"
BRANDS
brand_id brand_name brand_country_id
1 Example brand 1
2 Brand 2 2
Whisky
whisky_id whisky_brand_id
1 2
2 2
3 1
4 2
Country
country_id country_nicename
1 Poland
2 Germany
And i have SQL:
SELECT
brands.brand_id,
brands.brand_name,
brands.brand_country_id,
country.country_id,
country.country_niename
FROM
brands
LEFT JOIN
country
ON
brands.brand_country_id = country.country_id
LEFT JOIN
whisky
ON
brands.brand_id = whisky.whisky_brand_id
I'm want to data like
brand_id brand_name country_id country_nicename no.ofWhisky
2 Brand2 1 Germany 3
But i dont know how to count no of whisky in this query :/
can anyone help?
Thx :)
You just need to do aggregation using group by & count():
SELECT brands.brand_id, brands.brand_name, country.country_id, country.country_niename,
count(whisky_id) as no.ofWhisky
FROM brands LEFT JOIN
country
ON brands.brand_country_id = country.country_id LEFT JOIN
whisky
ON brands.brand_id = whisky.whisky_brand_id
GROUP BY brands.brand_id, brands.brand_name, country.country_id, country.country_niename;
SELECT brands.brand_id, brands.brand_name, brands.brand_country_id, country.country_id, country.country_niename ,temp.whiskycount
FROM brands LEFT JOIN country ON brands.brand_country_id = country.country_id
LEFT JOIN (
select count(*) as whiskycount, whisky_brand_id
from whisky
Group by whisky_brand_id
) temp ON brands.brand_id = whisky.whisky_brand_id

I want movie name from the given database

Performance table:
PerformanceId SingerId MovieId NumberofSongs
1 1 1 2
2 3 1 4
3 2 2 6
4 4 5 3
5 5 5 3
6 2 6 2
7 4 6 5
8 6 4 6
9 6 3 3
10 4 3 4
Singer table:
SingerId SingerName City DOB Gender
1 A Hyderabad 14-Apr-65 M
2 B Chennai 25-May-84 M
3 C Bangalore 14-Sep-78 F
4 D Hyderabad 17-Jan-70 M
5 E Hyderabad 18-Mar-87 F
6 F Bangalore 23-Aug-75 F
Movie table:
MovieId MovieName ReleaseDate
1 AAA 12-Jan-15
2 BBB 19-Sep-12
3 CCC 23-Jul-10
4 DDD 06-Oct-01
5 EEE 08-Nov-05
6 FFF 18-Apr-99
7 GGG 07-Aug-12
I would need to list the MovieId, MovieName in which both Male and Female singers are performed
(list the movieid, moviename in which male and femail singer ie both singer are performed in one movie)
Hi guys please help me out with this query i tried i am not getting exact query
Here's my query:
select * from movies a inner join performance b
on a.movie_id=b.movie_id where b.singer_id in
(select singer_id from singer where gender = 'F') c inner join
(SELECT SINGER_ID FROM SINGER WHERE gender = 'M') d
on c.singer_id=d.singer_id;
First create a view "MOVIE_ANALYSIS" where you'll have a list of all movies and if they've mixed singers or not:
CREATE VIEW MOVIE_ANALYSIS AS SELECT
M.MOVIEID ,
M.MOVIENAME,
(COUNT(DISTINCT S.GENDER) > 1) AS MIXED
FROM MOVIE M
INNER JOIN PERFORMANCE P ON P.MOVIEID = M.MOVIEID
INNER JOIN SINGER S ON S.SINGERID = P.SINGERID
GROUP BY M.MOVIEID ;
Then you'll get your final result with this query:
SELECT * FROM MOVIE_ANALYSIS WHERE MIXED IS TRUE ;
The reason I used an intermediate view is that in several SQL engines, you cannot use the computed "mixed" attribute directly in the same query with a group by. It'll keep insisting that mixed column is missing.
Validated and test on H2. I did not test on Oracle, as I've no access to it.
What you want here is the INTERSECT statement (using Oracle):
select movieId
from performance a
where exists (select 1
from singer b
where A.singerID = b.singerID
and b.gender = 'F')
intersect
select movieId
from performance a
where exists (select 1
from singer b
where A.singerID = b.singerID
and b.gender = 'M');
Then you just join the movie IDs you get back to the Movie table.
INTERSECT will only bring back IDs that are common to both queries (or however many you use).

Group by with two columns

I am trying to write a query using group by in sub query ,I referred lot of blogs but could not get all the values.
I have three tables and below is the structure of those tables.
Pet_Seller_Master
ps_id ps_name city_id
2 abc 1
3 xyz 2
4 fer 4
5 bbb 1
City_Master
city_id city_name
1 Bangalore
2 COIMBATORE
4 MYSORE
Api_Entry
api_id ps_id otp
1 2 yes
2 3
3 2 yes
4 3 yes
5 4
6 5 yes
7 5 yes
8 5 yes
Query is to get number of sellers, no of pet sellers with zero otp, no of pet sellers with 1 otp, no of pet sellers with 2 otp,no of pet sellers with otp>2 for the particular city and within date range.
Through Below query I am able to get city , psp , and zero otp
select cm.city_name,
count(ps.ps_id) as PSP,
((select count(ps1.ps_id)
FROM ps_master ps1
WHERE ps1.city = cm.city_id)-
(SELECT count(distinct ps1.ps_id)
from ps_master ps1
INNER JOIN api_entry ae ON ps1.ps_id = ae.ps_id and otp!=''
WHERE ps1.city = cm.city_id and date(timestamp) >= curdate() - INTERVAL DAYOFWEEK(curdate())+6 DAY AND date(timestamp) < curdate())) as zero_psp
from ps_master ps INNER JOIN city_master cm ON ps.city = cm.city_id and cm.city_type = 'IN HOUSE PNS'
group by city_id
Please tell me the solution to solve this query.
Thanks in advance
It's not hard to do and you were on a right track. Here is what I would use:
select c.city_name, a.otp, p.ps_name, COUNT(*) nbr
from Api_Entry a
inner join Pet_Seller_Master p on p.ps_id=a.ps_id
inner join City_Master c on p.city_id=c.city_id
group by c.city_name, a.otp, p.ps_name
Now, if you want to get the number of sellers with zero otp, you just apply where clause:
where otp <> 'yes'
If you want to get the number of pet sellers with otp>2, then you just use subquery:
select *
from (
select c.city_name, a.otp, p.ps_name, COUNT(*) nbr
from #tempA a
inner join #tempP p on p.ps_id=a.ps_id
inner join #tempC c on p.city_id=c.city_id
group by c.city_name, a.otp, p.ps_name
) g
where nbr > 2