简体   繁体   中英

SQL Query to perform division

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM