2

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
4

3 回答 3

2
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

fiddle

于 2013-03-04T08:11:53.267 回答
1

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.

于 2013-03-04T02:25:21.593 回答
0

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.

于 2013-03-04T03:46:15.477 回答