I'm trying to perform SQL division using Oracle, such that, all User_ID
that have teaches SAME classes as a specific ID, should be returned.
Table structures of both tables, I'm working with:
HUMAN(id, first, last)
INSTRUCTOR(human_id, location) -- PK(id, location)
CLASS(instructor_id, class_code, class_num) -- PK(instructor_id, class_code, class_num)
Query I'm currently working with:
SELECT DISTINCT instructor_id, class_code, class_num
FROM CLASS
WHERE NOT EXISTS (
(SELECT instructor_id, class_code, class_num FROM CLASS)
MINUS
(SELECT instructor_id, class_code, class_num
FROM CLASS
WHERE instructor_id =
(SELECT HUMAN.id
FROM HUMAN
WHERE first = 'Foo'
AND last = 'Bar')))
Sample data
HUMAN
id first last
1 foo bar
2 John Doe
INSTRUCTOR
human_id location
1 US
2 CA
CLASS
instructor_id class_code class_num
1 CS 999
1 MA 111
1 DE 222
2 CS 999
2 MA 111
2 DE 222
3 CS 999
4 CS 999
The query should return instructor_id 2
, since it is the only one that instructs same classes as instructor_id 1
The query I have returns no row, despite inserting data to match this scenario.
SELECT DISTINCT instructor_id, class_code, class_num
FROM CLASS
WHERE class_num IN (SELECT class_num from CLASS WHERE instructor_id = (SELECT HUMAN.id FROM HUMAN WHERE first = 'Foo' AND last = 'Bar'))
This will return all the instructors (including Foo Bar) which give the same class as Foo Bar.
If you want to exclude Foo Bar, just add another WHERE class (instructor_id != (SELECT HUMAN.id FROM HUMAN WHERE first = 'Foo' AND last = 'Bar'))
One of the ways:
with t as (
select distinct instructor_id id, class_num cn
from class
where instructor_id = (select id from human
where first = 'foo' and last = 'bar'))
select c.instructor_id as id, max(h.first||' '||h.last) as name
from class c
join human h on c.instructor_id = h.id
join t on t.cn = c.class_num and c.instructor_id <> t.id
group by instructor_id
having count(distinct class_num) = (select count(1) from t)
Test data and output:
create table HUMAN (id number(3), first varchar2(5), last varchar2(5));
insert into human values (1, 'foo', 'bar');
insert into human values (2, 'John', 'Doe');
create table INSTRUCTOR (human_id number(3), location varchar2(3));
insert into instructor values (1, 'US');
insert into instructor values (2, 'CA');
create table CLASS (instructor_id number(3), class_code varchar2(3), class_num number(4));
insert into class values (1, 'CS', 999 );
insert into class values (1, 'MA', 111 );
insert into class values (1, 'DE', 222 );
insert into class values (2, 'CS', 999 );
insert into class values (2, 'MA', 111 );
insert into class values (2, 'DE', 222 );
insert into class values (3, 'CS', 999 );
insert into class values (4, 'CS', 999 );
Output:
ID NAME
---- -----------
2 John Doe
What about this:
SELECT *
FROM instructor i
WHERE NOT EXISTS
(SELECT *
FROM class c
WHERE c.instructor_id = i.human_id
MINUS
SELECT *
FROM class c
WHERE instructor_id = (SELECT human.id
FROM human
WHERE FIRST = 'Foo' AND LAST = 'Bar'));
I assumed an instructor may teach the same class more than once (if they can't the query can be simplified somewhat). I also assumed that the input is given as "first name, last name' rather than directly a human.id, although that is a poor way to run queries; what if more than one instructor has the same first and last name? Parameters should use unique identifiers.
Anyway, here it is. It can be modified to accommodate changes in the data model or the input model; right now it is based on the OP's requirements as stated.
with sel(p_id) as (select id from human where first = 'foo' and last = 'bar'),
a(i, ct) as (select instructor_id, count(distinct class_code || class_num)
from class group by instructor_id)
select i from a join sel on i != p_id
where
(select count(distinct class_code || class_num) from class
where instructor_id in (p_id, i)) =
(select min(ct) from a a1 where a1.i in (p_id, a.i));
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.