집 짓는 개발블로그
[프로그래머스] 조건에 맞는 개발자 찾기 (MySQL) - EXISTS, 서브쿼리 본문
https://school.programmers.co.kr/learn/courses/30/lessons/276034
문제 요약: DEVELOPERS 테이블에서 SKILLS_CODE 컬럼의 값(INT)이, (SKILLCODES 테이블에서 NAME컬럼의 값이 'Python'과 'C#' 중 하나인 레코드들)의 CODE 컬럼의 값(INT)을 포함하는 레코드들을 select하면 된다. 논리 연산자 &나 |을 써서 포함관계를 판단할 수 있다.
소요시간: 17분
열심히 헤맸다.
포인트
1. MySQL의 쿼리 실행 순서
2. 서브쿼리에 대하여
정답
-- SKILL_CODE & CODE = CODE면 해당 개발자가 해당 스킬 가진 것
WITH WANTED_SKILLS AS(
SELECT CODE
FROM SKILLCODES
WHERE NAME IN ('Python', 'C#')
)
-- 서브쿼리 안에서 FROM D 바로 썼더니(메인쿼리의 별칭 바로 썼더니) 실패 (1146, "Table 'programmers.d' doesn't exist") 에러남
SELECT ID, EMAIL, FIRST_NAME, LAST_NAME
FROM DEVELOPERS D
-- EXISTS는 메인쿼리부터 접근하니까, 일단 D테이블의 한 데이터를 딱 잡음
-- 그 뒤에 서브쿼리 접근해서, 이 D테이블의 데이터의 SKILL_CODE와, WS테이블의 모든 CODE를 매칭해가면서 비교하고
-- WHERE조건을 만족하는 CODE가 있으면? (= 이 개발자가 파이썬이나 C# 갖고 있으면) EXISTS 조건이 TRUE
-- -> 이러한 개발자들의 데이터를 출력
WHERE EXISTS (SELECT * FROM WANTED_SKILLS WS WHERE D.SKILL_CODE & WS.CODE = WS.CODE)
ORDER BY ID;
일단 어제 공부한 EXISTS로 풀고 나서 여러 가지 시도해봤다. SQL 문제를 풀 때마다 아래와 같은 잘못된 풀이들로 대충 풀어버리고 싶은 충동이 샘솟는데 하나씩 실행해보고 왜 안 되는지를 확실히 알아두기 위함이다.
실패한 풀이 1
WITH WANTED_SKILLS AS(
SELECT CODE
FROM SKILLCODES
WHERE NAME IN ('Python', 'C#')
)
SELECT ID, EMAIL, FIRST_NAME, LAST_NAME
FROM DEVELOPERS D
WHERE D.SKILL_CODE & WANTED_SKILLS.CODE = WANTED_SKILLS.CODE
ORDER BY ID;
실패 (1054, "Unknown column 'WANTED_SKILLS.CODE' in 'where clause'")
이러면 메인쿼리에서 내가 만든 WANTED_SKILLS를 못 찾는다.
그래서 이렇게도 해봤다. 서브쿼리를 그냥 그 자리에 갖다넣어봤다.
실패한 풀이 2
SELECT ID, EMAIL, FIRST_NAME, LAST_NAME
FROM DEVELOPERS D
WHERE D.SKILL_CODE & (SELECT CODE
FROM SKILLCODES
WHERE NAME IN ('Python', 'C#')) = (SELECT CODE
FROM SKILLCODES
WHERE NAME IN ('Python', 'C#'))
ORDER BY ID;
실패 (1242, 'Subquery returns more than 1 row')
당연한 결과 감사합니다.
실험이 끝났으니 이제 공부하자.
1. MySQL의 쿼리 접근 순서
기본적으로 FROM - WHERE - GROUP BY - HAVING - SELECT - ORDER BY [ - LIMIT] 순서대로 실행된다.
따라서 GROUP BY 뒤에 어떤 컬럼명을 써서 해당 컬럼으로 데이터를 그룹핑했다면, 반드시 SELECT 뒤에도 해당 컬럼명을 써줘야 한다!
(코테에서는 별칭 위치가 헷갈리면 그냥 별칭을 안 쓰는 방향으로 타협본다. 🫠)
2. 서브쿼리
🔥서브쿼리 사용 시 주의점🔥
1) 서브쿼리에는 ; 를 붙이지 않는다
2) 서브쿼리 → 메인쿼리 순서대로 실행된다.
3) 2번 때문에 헷갈릴 수 있는데, 서브쿼리는 메인쿼리의 컬럼을 사용할 수 있다. 메인쿼리는 서브쿼리 거 못 쓴다.
서브쿼리는 3가지가 있다.
(1) 스칼라 서브쿼리(Scala Subquery)
- SELECT 뒤에 쓰이는 서브쿼리
- 다른 테이블에서 '값 하나'만 가져올 때 주로 사용.
SELECT M.GENDER, (SELECT MAX(ID) FROM OTHER_TABLE WHERE GENDER = M.GENDER) AS 'SUB'
FROM MAIN_TABLE M
- 반드시 한 번에 하나의 레코드만 리턴해야 함!
- 위 예시에서는 '"M의 GENDER컬럼의 어떤 값와 GENDER컬럼의 값이 일치"하는 OTHER_TABLE의 레코드들 中' ID의 최댓값 하나씩을 뽑아 SELECT한다.
- 일치하는 데이터가 없으면 NULL 이 나온다.
M.GENDER | SUB |
Female | 32 |
Male | 40 |
Etc |
위와 같은 형태의 결과가 나올 것이다. 맨 마지막은 NULL이다.
(2) 인라인 뷰(Inline View)
- FROM 뒤에 쓰이는 서브쿼리
- FROM 뒤에 서브쿼리를 사용한다면 반드시 [AS] '__' 으로 Alias를 붙여줘야 한다. 🔥
06/27/24 수정 - 작은따옴표 붙이면 에러 난다. 큰따옴표 붙여도 에러 난다. 그냥 [AS] SUB 이렇게 해줘야 한다!
(3) 중첩 서브쿼리(Nested Subquery)
- WHERE 뒤에 쓰이는 서브쿼리
- SELECT된 레코드가 딱 하나면 WHERE절에서 바로 비교 연산자 뒤에 써도 된다. 하나가 아니라면, all 또는 any로 전체를 감싸서 쓸 수도 있다. (예시: WHERE MAIN.AGE > ALL(SELECT AGE FROM SUB_TABLE) )
다 공부하고 나서 다른 방법으로 풀어보려고 시도했는데 실패함. 조인하기엔 컬럼이 없다. 나중에 돌아와서 다시 생각해봐야겠다.
'MySQL' 카테고리의 다른 글
[프로그래머스] 업그레이드 된 아이템 구하기 (MySQL) - INNER JOIN으로 NULL 바로 제거하기, EXISTS (0) | 2024.06.23 |
---|---|
[프로그래머스] LV.3 숫자 게임 (Python) - deque (0) | 2024.06.22 |
[프로그래머스] 업그레이드 할 수 없는 아이템 구하기 (MySQL) - IN, EXISTS, NULL, Three-valued logic (0) | 2024.06.21 |
[프로그래머스] 헤비 유저가 소유한 장소 (MySQL) (0) | 2024.06.21 |
[프로그래머스] 부모의 형질을 모두 가지는 대장균 찾기 (MySQL) - 비트 연산자 &, |, ^ (0) | 2024.06.20 |