Reputation: 13747
I have three Oracle database tables. I'll create a contrived example to make it a little easier:
A table of veterinarians ..
vid name
1 Bob
2 Sally
3 Sue
4 Henry
Specialties
spid Animal
1 Dogs
2 Cats
3 Mice
4 Kangaroos
5 Koala Bears
Advertising
id vid spid Ad venue
1 1 1 TV ads
2 1 2 TV ads
3 1 2 Magazine ads
4 2 1 TV ads
5 2 1 On line ads
6 3 5 TV ads
7 4 5 Magazine ads
I'd like to get a result set of the first 3 vets that advertise just one speciality, for each specialty. It is possible that for some specialties, NO vet just advertises that one speciality. The 'vets' table has about 30,000 rows in it. The Specialties table just has 10 rows. The advertising table has about 100,000 rows. I know how to do queries and joins, but don't have an idea for how to find rows that are all the same within the group.
So I'm looking for output like this:
Dogs null
Cats Sally
Mice null
Kangaroos null
Koala Bears Sue, Henry
Upvotes: 2
Views: 959
Reputation: 4077
try the following :-
select vid
from (select distinct vid, spid
from advertising)
group by vid
having count(*) = 1;
the above will give you a list of all those vets which have only 1 speciality. To get a list of the corresponding specialities, execute the following :-
select * from
(select s.spid,s.animal, a.vid,v.name,row_number() over (partition by s.spid order by a.vid) rn
from specialities s inner join advertising a
on s.spid=a.spid
inner join vets v
on a.vid=v.vid
and v.vid in (select vid
from (select distinct vid, spid
from advertising)
group by vid
having count(*) = 1)
order by s.spid
)
where rn <= 3;
The above will not show those specialities which should have null output (according to your example). To get that list also, convert the last inner join to a left outer join.
Upvotes: 0
Reputation: 23737
select
max(animal) as animal,
listagg(name, ', ') within group (order by name) as vet_list
from
Specialties
left join (
select
vid,
max(spid) as spid,
row_number() over(partition by max(spid) order by null) rn
from Advertising
group by vid
having count(distinct spid) = 1
) using(spid)
left join veterinarians using(vid)
where lnnvl(rn > 3)
group by spid
order by spid
Upvotes: 2
Reputation: 2473
This gives you the vets who only advertise 1 specialty
SELECT vid
FROM advertising
GROUP BY vid
HAVING COUNT(*)=1
This gives you all the vets with 1 specialty in each category
SELECT s.Animal, v.name
FROM Specialties s
LEFT JOIN
advertising a ON s.spid=a.spid
LEFT JOIN
veterinarians v ON a.vid=v.vid
WHERE a.vid IN (SELECT vid
FROM advertising
GROUP BY vid
HAVING COUNT(*)=1)
Now, you haven't specified what "first" means in this context - alphabetically, by id, something else? When you decide that, you can partition by this.
Upvotes: 1