참조 : The Programmer's Guide to SQL

두 개 이상의 테이블의 데이터가 필요할 때 서브쿼리나 조인을 사용할 수 있다. 이번 챕터는 서브쿼리에 대해 공부한다.

서브쿼리에는 두종류가 있다.

  • 독립적인 서브쿼리 non-correlated subquery : 포함된 쿼리가 한 번만 수행되며, 그 결과가 외부 쿼리에 전달된다.
  • 연관된 서브쿼리 correlated : 외부 쿼리의 데이터를 필요로 하며, 외부 쿼리의 결과 레코드 마다 한 번씩 수행하게 된다.

성능은 당연히 독립적인 서브쿼리가 좋아보인다. 그렇다고 연관된 서브쿼리를 안 쓸 수도 없을테고 외부 쿼리Outter Query의 레코드 수를 줄이면 그나마 Inner Query 수행 횟수가 줄어 들테니 이 점을 유의해야겠다.

연관된 서브쿼리 예제1

SELECT CustomerID, CustomerName, (
   SELECT COUNT(*) FROM CreditCards
   WHERE CreditCards.CustomerID = Customers.CustomerID)
   AS NumberOfCreditCards
FROM Customers

- 고객ID, 고객이름, 고객의 신용카드 거래 합계를 보여준다.
- Customers 테이블의 레코드 갯 수 만큼 서브 쿼리가 실행된다.

연관된 서브쿼리 예제2

SELECT e1.StudentID, e1.ClassID, (
   SELECT COUNT(*) FROM Enrollment e2
   WHERE e1.ClassID = e2.ClassID)—1
   AS OtherStudentsInClass
FROM Enrollment e1
WHERE StudentID = 6;

- ID가 6인 학생이 등록한 수업에 참여하는 다른 학생들의 합계를 구한다.
- Enrollment 테이블에서 SudentID가 6인 레코드 갯수 만큼 서브쿼리를 수행한다.

독립적인 서브쿼리 예제 1

SELECT ExamID, SustainedOn FROM Exam
WHERE SustainedOn <= (
   SELECT SustainedOn FROM Exam WHERE ExamID = 5)
ORDER BY SustainedOn DESC;

- 시험 ID가 5인 시험이 치뤄지기 이전에 치뤄진 모든 시험 목록을 역순으로 보여준다.
- 내부 쿼리는 한 번만 수행되고 그 결과를 외부 쿼리에서 사용한다.

독립적인 서브쿼리 예제 2

SELECT StudentID, Name FROM Student WHERE StudentID IN
  (SELECT StudentID FROM Enrollment WHERE ClassID IN
        (SELECT ClassID FROM Class WHERE ProfessorID IN
          (SELECT ProfessorID FROM Professor
          WHERE Name LIKE '%Williams%')));

- Williams 라는 이름이 들어가는 교수가 가르치는 학급에 등록한 학생들의 정보를 보여준다.
- 역시 전부 독립적인 서브쿼리로 여러개의 결과를 반환하기 때문에 IN을 사용했다.

EXISTS 연산자
- 외부 쿼리의 결과 레코드가 내부 쿼리 레코드 집합안에 포함되어 있다면, true.
- 따라서 연관된 쿼리로 작성해야 함.
- 따라서 a.커럼id = b.컬럼id 와 같은 공식이 내부 쿼리에 추가되어야 함.
- 그래야 외부 쿼리와 내부 쿼리가 연결 됨.

- 예제
SELECT StudentID, Name FROM Student s
WHERE EXISTS (
   SELECT StudentID FROM StudentExam e
   WHERE Mark < 40 AND e.StudentID = s.StudentID);
- Mark가 40점 이하인 학생 정보.
- AND e.StudentID = s.StudentID 없으면 그냥 Student 테이블의 모든 레코드 보여줌.

ALL 연산자
- 외부쿼리가 ALL 뒤에 있는 내부 쿼리의 결과를 모두 만족 시키는 경우 true.

-예제
SELECT StudentID, Grade FROM Enrollment e
WHERE Grade > ALL (
   SELECT Mark FROM StudentExam s
   WHERE s.StudentID = e.StudentID);
- 등록 정보 중에서 Grade가 그 학생이 치룬 모든 시험의 Mark보다 높은 학생 정보를 보여줌.

ANY 연산자
- 외부쿼리가 ANY 뒤에 있는 내부 쿼리의 결과에 하나라도 만족하는 경우 true.

- 예제
SELECT StudentID, Grade FROM Enrollment e
WHERE Grade < ANY (
   SELECT Mark/2 FROM StudentExam s
   WHERE s.StudentID = e.StudentID);
-등록 정보 중에서 Grade가 그 학생이 치룬 모든 시험의 Mark의 절반도 안되는 학생 정보를 보여줌.

쿼리 결과 데이터 조합하기
SELECT ColumnA, ColumnB FROM TableA
<Operator>
SELECT ColumnC, ColumnD FROM TableB;

Operator(오라클)

  • UNION : 합집합
  • UNION ALL : 합집합 + 교집합
  • INTERSECT : 교집합
  • MINUS : 차집합

흠.. EXISTS, ALL, ANY 어렵... -_-;;