본문 바로가기
C.W.K.
Stream
Lesson 07 of 10 · published

Subquery — Inline SELECT

~12 min · sql, subqueries, scalar-subquery

Level 0Scout
0 XP0/80 lessons0/10 achievements
0/120 XP to next level120 XP to go0% complete

SELECT 안의 SELECT

Subquery는 다른 statement 안에 들어앉은 SELECT야. 자주 보는 모양이 넷 있어.

  • Scalar subquery — 값 하나를 돌려주니까 컬럼 자리나 비교식에 넣어 쓸 수 있어. SELECT name, (SELECT count(*) FROM messages WHERE conversation_id = c.id) AS n FROM conversations c;
  • IN subquery — 값의 묶음을 돌려주고 IN의 오른쪽에 앉아.
  • EXISTS subquery — 있냐 없냐만 돌려줘. WHERE EXISTS (SELECT 1 FROM messages m WHERE m.conversation_id = c.id).
  • Derived 테이블 — FROM 자리에 통째로 들어가. FROM (SELECT brain, count(*) AS n FROM messages GROUP BY brain) AS sub WHERE sub.n > 100;
Tip: subquery는 대부분 join이나 CTE로 다시 쓸 수 있고, 그쪽이 더 빠를 때도 있어. EXPLAIN QUERY PLAN으로 비교해봐. track 5에서 다뤄. 로직이 여러 겹으로 파고들면 track 7의 CTE가 보통 겹겹이 쌓인 subquery보다 훨씬 잘 읽혀.

Code

Subquery 4 모양·sql
-- 컬럼으로 scalar subquery
SELECT c.id, c.title,
       (SELECT count(*) FROM messages m WHERE m.conversation_id = c.id) AS n_messages
FROM   conversations c
ORDER  BY n_messages DESC LIMIT 10;

-- IN subquery
SELECT * FROM messages
WHERE  conversation_id IN (
  SELECT id FROM conversations WHERE archived = 0
);

-- EXISTS subquery (큰 set 에선 IN 보다 빠를 때 많음)
SELECT * FROM conversations c
WHERE  EXISTS (SELECT 1 FROM messages m WHERE m.conversation_id = c.id);

-- FROM 의 derived 테이블
SELECT day, total FROM (
  SELECT date(created_at) AS day, count(*) AS total
  FROM messages GROUP BY day
) WHERE total > 100;

External links

Exercise

테이블 두 개가 얽힌 그럴듯한 시나리오를 골라(conversations와 messages여도 되고 네 데이터여도 돼). 논리적으로 같은 결과를 내는 query를 네 가지로 써봐. scalar subquery, IN subquery, EXISTS subquery, 그리고 JOIN에 GROUP BY. EXPLAIN QUERY PLAN으로 넷을 비교하고, SQLite가 어느 쪽에 가장 단순한 plan을 골랐는지, 왜 그랬는지 적어.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.