database.sarang.net
UserID
Passwd
Database
DBMS
MySQL
PostgreSQL
Firebird
ㆍOracle
Informix
Sybase
MS-SQL
DB2
Cache
CUBRID
LDAP
ALTIBASE
Tibero
DB 문서들
스터디
Community
공지사항
자유게시판
구인|구직
DSN 갤러리
도움주신분들
Admin
운영게시판
최근게시물
Oracle Q&A 41728 게시물 읽기
No. 41728
기초sql 구문 질문
작성자
공시생
작성일
2019-06-14 10:54:46
조회수
224

안녕하세요. 전산직 공무원 준비를 하고 있는 사람입니다.

sql 문제에서 학원 선생님의 수업을 듣고도 무슨 소리인지 된통 알 수가 없어 

인터넷으로 이리저리 검색하다가 DATABASE.SARANG.NET을 찾게 되어 이렇게 고수님들께 질문 드립니다.

 

문제)

다음 EMPLOYEE, PROJECT, WORKSON 테이블로 구성된 데이터베이스에서  "모든 프로젝트에 참가하는 직원의 이름을 검색하라"를 수행하기 위한 SQL문으로 옳은 것은?

 

EMPLOYEE(eNo, eName)

PROJECT(pNo, pName)

WORKSON(eNo, pNo)

 

정답)

SELECT eName

FROM EMPLOYEE E

WHERE NOT EXISTS(

       SELECT P.pNo

        FROM PROJECT P

        WHERE NOT EXISTS(

                SELECT W.pNo

                FROM WORKSON W

                WHERE P.pNo = W.pNo AND E.eNo = W.eNo

      )

);

 

위의 sql 문장이 정답인데요. 

먼저 부속질의와 조인에 대한 기본적인 개념은 확실히 알고 있습니다.

그런데 제일 안쪽 부속질의를 보면 WHERE 문장에서 부속질의 바깥 부분의 PROJECT 테이블 참조를 볼 수 있는데

어떻게 안쪽 부속질의에서 조인을 하지 않았는데 가져다 쓸 수 있는 것이죠??

그리고 부속질의의 결과는 P.pNo이고 처음 질의는 EMPLOYEE 테이블에서의 WHERE절이고 EMPLOYEE에는 pNo 속성이 있지도 않은데 어떻게 비교를 할 수 있는 것이죠?


그래서 저는 부속질의를 하면 자동으로 조인 된다던가, 아니면 그냥 참조가 가능하게끔 DBMS가 통제를 해준다던가라고만 생각했었습니다.

 

 

다음은 다시 제일 안쪽 부속질의를 보면 여기서는 한 명이라도 프로젝트에 참가한 직원의 pNo을 출력할 것이고

그 다음 부속질의에서는 한 명도 참가하지 않은 pNo이 출력될 것입니다.

그럼 최종적으로 한 명도 참가하지 않은 pNo의 NOT EXISTS이니 다시

한 명이라도 프로젝트에 참가한 직원의 pNo을 출력하는 거 아닌가요??

계속 생각해본 결과 

SELECT eName FROM EMPLOYEE E WHERE NOT EXISTS 괄호 안에는

한 명이라도 참가한 프로젝트와 한명도 참가하지 않은 프로젝트가 들어있으니깐

그것을 뺀 나머지는 모두 참가하는 건가?? 라고 생각했습니다.

그런데 한 명이라도 참가한 프로젝트는 모든 프로젝트에 참가한 직원의 프로젝트도 포함되어 있는데 

그럼 출력이 0이 되야 하는거 아닌가요??

 

 

제 생각으로는 첫번째, 두번째 질문에 대한 이해가 떨어져서 이 문제의 이해를 못하고 있는 것 같습니다.

장황하게 썼는데 공무원 데이터베이스 시험에서 SQL문은 고득점을 받는냐 안 받는냐의 기로가 되는 문제입니다.

고수님들 잘 좀 부탁드리겠습니다.

이 글에 대한 댓글이 총 5건 있습니다.

 쿼리문을 말로 풀이하면

모든 직원 중

프로젝트가 존재하지 않은 (참여하지 않은) = 모든 프로젝트에 참가한

사람을 보여줘.

 

존재성 필터로 사용되는 EXISTS와 NOT EXISTS의 실행은

메인쿼리의 결과를 사용해 체크 한다고 보시면 됩니다.

 

일반적으로 조건절의 SUB쿼리가 먼저 실행 된 후 그 결과로 메인쿼리를 실행하는 것과는 반대상황입니다.

 

그리고 부속질의 결과가 P.pNo가 아님.

존재성 체크 이기 때문에 true / false만 반환됩니다.

박인호(paerae)님이 2019-06-14 15:32:05에 작성한 댓글입니다.
이 댓글은 2019-06-14 15:32:48에 마지막으로 수정되었습니다.

 답변 정말 정말 감사합니다.

 

EXISTS와 NOT EXISTS의 실행은 메인쿼리의 결과를 사용해 체크한다는 내용은 

정말 유익하였습니다.

 

그런데도 이해가 잘 되지 않아서 염치 불구하고 이렇게 한번 더 질문 드립니다.

 

true와 false를 반환한다는게 쿼리의 어느 부분인지 알고 싶습니다.

 

제가 질문드린 쿼리를 예로 들자면

 

가장 안쪽 서브쿼리 결과는 WORKSON 테이블에 있는 모든 pNo이 나올 것이고 

 

다음 서브쿼리에서는 PROJECT 테이블의 모든 튜플 중 위에서 나온 결과가 존재하지 않은

 

pNo의 결과가 나온다고 밖에 이해가 안됩니다.

 

true/false가 반환된다면 메인쿼리의 EMPLOYEE 테이블에서는 true/false만 보고 

 

어떻게 모든 직원의 이름을 검색해 내는거죠??

 

그리고 EXISTS와 NOT EXISTS 실행이 아닌 서브쿼리도 메인쿼리의 결과를 사용하는 건가요??

 

 

 

공시생님이 2019-06-14 19:27:10에 작성한 댓글입니다. Edit
SELECT eName
FROM EMPLOYEE E
WHERE NOT EXISTS(
       SELECT 1
        FROM PROJECT P
        WHERE NOT EXISTS(
                SELECT 1
                FROM WORKSON W
                WHERE P.pNo = W.pNo AND E.eNo = W.eNo
                AND rownum=1
      )
      AND rownum=1
);

논리적으로 이해하기 조금 쉽게

위와같이 쿼리를 변경해도 동일한 결과가 나옵니다.

EXISTS 구문이 가장 안쪽 서브쿼리 부터 실행되는 것이 아니라

밖에서 부터 안쪽으로 방향성이 있습니다.

메인쿼리가 다른 검색조건이 없기 때문에

EMPLOYEE 테이블 전체 내용을 가지고

EXISTS 구문의 존재성 체크 합니다.

첫 서비쿼리에 PROJECT 하고는 검사 조건이 없기 때문에

1번째 사원, 모든프로젝트 를 가지고

두번째 서브쿼리인 WORKSON을 검사하게 됩니다.(두번째 서비 쿼리에서는 사원속성(컬럼) 전체, 프로젝트 속성 전체를 사용할 수 있습니다.)

그래서 모든 프로젝트중 참여하지 않은 건이 하나라도 있으면  

해당 PROJECT 가 존재한다(TRUE) 가 되어

앞에 NOT 연산을 하면 FALSE가 되어 해당 사원 ROW는 제거 됩니다.

이런식으로 한ROW씩 검사가 된다고

이해하면 됩니다. (실제로는 집합연산이지만)

즉 모든 프로젝트에 참여한 EMPLOYEE만 남게 되는 거죠.

 

EXISTS와 대비되는 것이 IN 절 서브 쿼리인데

이건 서브쿼리가 먼저 실행되기 때문에 서브쿼리에서 메인쿼리의 결과를 사용할 수 없습니다.

박인호(paerae)님이 2019-06-14 20:28:23에 작성한 댓글입니다.
이 댓글은 2019-06-14 20:40:39에 마지막으로 수정되었습니다.

 사원에 A,B,C 가 있고

프로젝트가 1,2,3이 있고

참여프로젝트가 (A,1),(A,2),(A,3),(B,1) 있다고 한다면

A 로 조건 체크를 하면

A * (1,2,3) 으로 참여프로젝트를 체크를 하면 참여하지 않은 ROW 가 없어 FALSE

앞에 NOT이 있어서 TRUE 가 되어 사원 A는 표시

 

B로 조건 체크

B*(1,2,3) 으로 참여 프로젝트 체크 

1번 TRUE -( NOT)-> FASE ( 1제거)

2번 FALE -(NOT)-> TRUE ( 2반환) -(NOT)-> FALSE ( B 제거)

 

이런 논리 입니다.

박인호(paerae)님이 2019-06-14 20:55:42에 작성한 댓글입니다.
이 댓글은 2019-06-14 20:56:46에 마지막으로 수정되었습니다.

 자세한 설명 정말 감사합니다.

 

결국 EXISTS를 사용하는 서브쿼리는 메인쿼리에서 찾으려는 속성을 제일 안쪽 서브쿼리에서 

찾는다는 의미인거죠???? 그래서 방향성도 밖에서 안으로인 것이고요.

 

이 문제를 그냥 포기할까도 생각했는데 포기하지 않고 검색한 결과 이렇게 귀인을 만나게 되었네요.

 

다시 한번 진심으로 감사드리고 또 어려운 문제가 있을 때 도움 부탁드립니다.

 

 

공시생님이 2019-06-15 10:48:14에 작성한 댓글입니다. Edit
[Top]
No.
제목
작성자
작성일
조회
41732구분자별 시작일 종료일을 구하는 sql 조언 부탁드립니다. [4]
개발자
2019-06-18
202
41730오라클 테이블 스키마 백업시.. [1]
권기혁
2019-06-18
148
41729Pro*C 관련 에러 [PCC-S-02338, structure contains a nested struct or union]
WalkeR
2019-06-14
162
41728기초sql 구문 질문 [5]
공시생
2019-06-14
224
4172711g 로컬DB 설정 에러
신승익
2019-06-11
178
41726토드 limit 설정관련 문의드립니다. [1]
궁금증
2019-06-03
269
41725안녕하세요. SELECT 구문 조회 시 컬럼 골고루 섞어서 조회하는 방법 문의드립니다. [1]
동물애호가
2019-06-03
290
Valid XHTML 1.0!
All about the DATABASE... Copyleft 1999-2019 DSN, All rights reserved.
작업시간: 0.071초, 이곳 서비스는
	PostgreSQL v11.3으로 자료를 관리합니다