이번 게시글도 마찬가지로 개념 설명을 다소 적을 예정입니다.
다만, 이전 게시글과는 다르게 오답 과정 부분은 별로 없으니 안심(?)하셔도 될 겁니다 ㅎㅎ..


ANIMAL_INS 테이블과 ANIMAL_OUTS 테이블,
이전 게시글에서 봤던 테이블들입니다.
*테이블
1.ANIMAL_INS(ANIMAL_ID, ANIMAL_TYPE, DATETIME, INTAKE_CONDITION, NAME, SEX_UPON_INTAKE)
2.ANIMAL_OUTS(ANIMAL_ID(FK이자 PK인 느낌이 남. FK는 맞음.), ANIMAL_TYPE, DATETIME, NAME, SEX_UPON_OUTCOME)
※개념_1
'부모-자식 관계에서 식별 관계에서, 1:1 관계 및 1:N 관계에 따라서, 자식의 FK가 PK의 일부에 속하는 정도가 다르다.'
위 말이 잘 이해가 안 되실 거 같습니다.
해당 ANIMAL_OUTS 테이블 속성을 살펴보면,
ANIMAL_ID가 FK이자 단독 PK임을 알 수 있습니다.단독 PK인 이유는,
해당 사진에 있는 글을 보면,
슈퍼키(튜플(행)을 구분할 수만 있으면 슈퍼키 만족) -> 후보키(슈퍼키들 중 최소 속성 집합) -> 기본키(후보키들 중 하나 고른 키)이고, 기본키는 최소 속성을 가지는 키임을 알 수 있습니다.고로, ANIMAL_ID는 ANIMAL_OUTS 테이블에서도 혼자서 기본키 역할이 가능하므로 홀로 PK가 됩니다.
근데, 저는 여기서 의문이 든 점이
'부모 자식 관계 식별 관계에서 FK 혼자만으로 PK가 가능한가?
내가 아는 것은 FK가 PK의 일부인 거 밖에 없는데?'
입니다.이는 맨 위에 나뉜것처럼 1:1 OR 1:N에 따라서 달라집니다.
제가 사진 첨부를 한 것은 1:1 관계로 FK 혼자서 PK가 가능합니다.
하지만, 1:N의 관계에서는 FK는 PK의 일부여야하고, 단독 PK가 불가능합니다.
*문제
1.보호소에서 중성화 수술을 거친 동물들 정보를 알고자 함.
2.보호소에 들어올 때는(ANIMAL_INS) 중성화 X이지만, 보호소 나갈 때에는(ANIMAL_OUTS) 중성화 O인 동물들 중에,
->중성화 X: INTACT, 중성화 O: SPAYED OR NEUTERED3.ANIMAL_ID, ANIMAL_TYPE, NAME 조회하기
<정답 코드>
SELECT
ANIMAL_ID,
ANIMAL_TYPE,
NAME,
SEX_UPON_INTAKE
FROM ANIMAL_INS
WHERE SEX_UPON_INTAKE LIKE '%INTACT%'
일단 저는 SELECT문에서 저 열들을 알고 싶어서(정답과 무관하게) 선택을 했고,
여기서 유심히 볼 점은 새로운 개념인 WHERE절의 '패턴 매칭'입니다.
※개념_2. 패턴 매칭
SQL에서 패턴 매칭에는 %라는 와일드카드를 사용합니다.
'문자열%'의 의미는 '문자열'로 시작하는 문자열을 찾는 것이고, '%문자열'의 의미는 '문자열'로 끝나는 문자열을 찾는 것이고, '%문자열%'는 '문자열'을 포함한 문자열을 찾는 것입니다.
EX.) 1. '문자열%' : 문자열1, 문자열2, 문자열3,... 2. '%문자열' : 1문자열, 2문자열, 3문자열,... 3. '%문자열%' : 1문자열2, 12문자열, 문자열12,...또한, 패턴 매칭 연산자는 '='이 아닌 LIKE를 사용해야하며,
WHERE/IN과 LIKE를 같이 붙여서 쓸 수 없습니다.
'WHERE/IN'은 해당 리스트에서 고르는(선택하는) 문법이므로, 부분 문자열이 포함되지 않기 때문입니다.
해당 개념 부분은 뒷부분에도 나올 예정이니, 그 때 또 설명하도록 하겠습니다.
여기서는 '서브쿼리 + 조인' 방법을 이용해야 합니다.
위 2-1을 서브쿼리로 넣고,
FROM에서 서브쿼리를 넣었으니 파생 테이블(DERIVED TABLE)에 별칭을 붙이고,
파생 테이블과 ANIMAL_OUTS를 'ANIMAL_ID'라는 공통된 속성을 사용하여 INNER JOIN합니다.
INNER JOIN하는 이유는, 2-1일 때, 2-2를 구하는 과정이므로 교집합이어야 하기 때문입니다.
->'ANIMAL_ID'는 PK이자 FK이므로 공통된 속성으로 제 격입니다.

<정답 코드>
SELECT
AO.ANIMAL_ID,
AO.ANIMAL_TYPE,
AO.NAME,
T_1.SEX_UPON_INTAKE,
AO.SEX_UPON_OUTCOME
FROM
(SELECT
ANIMAL_ID,
ANIMAL_TYPE,
NAME,
SEX_UPON_INTAKE
FROM ANIMAL_INS
WHERE SEX_UPON_INTAKE LIKE '%INTACT%') AS T_1 INNER JOIN ANIMAL_OUTS AO
ON T_1.ANIMAL_ID = AO.ANIMAL_ID
-- WHERE AO.SEX_UPON_OUTCOME LIKE IN ('%NEUTERED%','%SPAYED%');
-- WHERE AO.SEX_UPON_OUTCOME LIKE '%NEUTERED%' OR AO.SEX_UPON_OUTCOME LIKE '%SPAYED%';
※개념_3. 파생 테이블(DERIVED TABLE) 최종 정리
즉, 요약하자면,
파생 테이블은 한 SELECT문 내에서(';' 내에서. 보통 SELECT문이 끝나면 ;을 사용하므로) 일반 테이블과 거의 유사한 기능을 가집니다.따라서, 위 제 정답 코드 같이 INNER JOIN 또한 가능합니다.
다만, FROM에서 서브쿼리를 만들었기 때문에, FROM은 테이블이 필요하므로 별칭(ALIAS)가 필수입니다.
그럼 이제, 저 위 정답 코드에서 'ANIMAL_OUTS'에서 중성화 O인 WHERE 조건절만 작성하면 완성입니다.
<최종 정답 코드>
SELECT
AO.ANIMAL_ID,
AO.ANIMAL_TYPE,
AO.NAME
-- T_1.SEX_UPON_INTAKE,
-- AO.SEX_UPON_OUTCOME
FROM
(SELECT
ANIMAL_ID,
ANIMAL_TYPE,
NAME,
SEX_UPON_INTAKE
FROM ANIMAL_INS
WHERE SEX_UPON_INTAKE LIKE '%INTACT%') AS T_1 INNER JOIN ANIMAL_OUTS AO
ON T_1.ANIMAL_ID = AO.ANIMAL_ID
-- WHERE AO.SEX_IPON_OUTCOME LIKE IN ('%NEUTERED%','%SPRAYED%');
WHERE AO.SEX_UPON_OUTCOME LIKE '%NEUTERED%' OR AO.SEX_UPON_OUTCOME LIKE '%SPAYED%';
여기서 WHERE 절을 잘 봐주세요.
※개념_4.
위 개념_2에서, 'WHERE/IN과 LIKE를 같이 붙여서 쓸 수 없습니다.'의 연장 개념입니다.
여기서는 '%NEUTERED%' OR '%SPAYED%'가 포함된 동물들만 구해야합니다.
위 개념_2에서 말한 것처럼,
WHERE/IN 개념은 확실하게 리스트 안에 있는 값들에 속해있는지 아닌지를 파악하는 문법이기 때문에, 부분 문자열이 아닌 완전 문자열 개념입니다.따라서, IN과 LIKE는 같이 쓸 수가 없습니다.
따라서 위 최종 정답 코드에 나와있는 것처럼,
WHERE AO.SEX_UPON_OUTCOME LIKE '%NEUTERED%' OR AO.SEX_UPON_OUTCOME LIKE '%SPAYED%';이렇게 절을 따로 써서 OR로 붙여야합니다.

이로써 이번 프로그래머스 LEVEL_4 문제를 풀어보았습니다.
이전 게시글에서 나온 개념들과 거의 유사하게 반복되어서,
어렵지 않게 문제를 해결할 수 있었습니다.
이번에도 제 긴 글을 읽어주셔서 감사합니다!! :) bb