09 SQL SELECT 세부 명령어 실습 1
1. 인트로
SELECT의 강력한 세부 기능인 ORDER BY(오더 바이), DISTINCT(디스팅트), LIKE(라이크), IN(인)을 깊이 있게 익힌다. 이 기능들로 원하는 데이터를 정확하게 추출하는 능력을 키운다.
2. 실습 DB 준비
1import sqlite32import pandas as pd3
4conn = sqlite3.connect("webtoon.db")5cur = conn.cursor()6
7cur.execute("""8 CREATE TABLE IF NOT EXISTS webtoons (9 id INTEGER PRIMARY KEY AUTOINCREMENT,10 title TEXT NOT NULL,11 author TEXT,12 genre TEXT,13 platform TEXT,14 score REAL,15 views INTEGER,16 complete INTEGER DEFAULT 017 )18""")19
20webtoons = [21 ("나 혼자만 레벨업", "추공", "액션", "카카오페이지", 9.8, 50000000, 1),22 ("전지적 독자 시점", "싱숑", "판타지", "카카오페이지", 9.7, 45000000, 1),23 ("신의 탑", "SIU", "판타지", "네이버웹툰", 9.5, 40000000, 0),24 ("외모지상주의", "박태준", "드라마", "네이버웹툰", 9.2, 60000000, 0),25 ("마스크걸", "마일", "스릴러", "네이버웹툰", 8.9, 20000000, 1),26 ("재혼황후", "알파타르트", "로맨스", "카카오페이지", 9.1, 35000000, 1),27 ("입학용병", "이 일규", "액션", "네이버웹툰", 8.7, 18000000, 1),28 ("화산귀환", "비가", "무협", "카카오페이지", 9.6, 42000000, 0),29 ("역대급 영지", "야유", "판타지", "네이버웹툰", 8.5, 12000000, 0),30 ("쌉니다 천리마마트","김규삼","드라마", "네이버웹툰", 9.0, 22000000, 1),31]32
33cur.executemany(34 "INSERT INTO webtoons (title,author,genre,platform,score,views,complete) VALUES (?,?,?,?,?,?,?)",35 webtoons36)37conn.commit()38print("웹툰 데이터 삽입 완료")3. ORDER BY(오더 바이) 정렬 실습
3.1. 단일 기준 정렬
1# 조회수 높은 순으로 정렬2df = pd.read_sql(3 "SELECT title, views FROM webtoons ORDER BY views DESC",4 conn5)6print(df)3.2. 다중 기준 정렬
1# 장르 오름차순, 같은 장르 내에서는 점수 내림차순2df = pd.read_sql(3 "SELECT title, genre, score FROM webtoons ORDER BY genre ASC, score DESC",4 conn5)6print(df)코드 설명:
- 3행:
ORDER BY genre ASC, score DESC— 먼저 genre로 정렬하고, 같은 genre 내에서는 score 내림차순으로 정렬한다. - 콤마(
,)로 여러 정렬 기준을 지정할 수 있다.
4. DISTINCT(디스팅트)를 활용한 중복 제거 실습
4.1. 중복 없이 플랫폼 목록 조회
1cur.execute("SELECT DISTINCT platform FROM webtoons")2platforms = cur.fetchall()3print("=== 플랫폼 목록 ===")4for p in platforms:5 print(f" - {p[0]}")실행 결과:
1=== 플랫폼 목록 ===2 - 카카오페이지3 - 네이버웹툰코드 설명:
- 1행:
SELECT DISTINCT platform— platform 컬럼에서 중복을 제거한 고유값만 가져온다. - DISTINCT가 없으면 같은 플랫폼 이름이 여러 번 반복된다.
4.2. 다중 컬럼 DISTINCT
1# 장르와 플랫폼 조합의 중복 제거2df = pd.read_sql(3 "SELECT DISTINCT genre, platform FROM webtoons ORDER BY genre",4 conn5)6print(df)코드 설명:
- 두 컬럼 모두 동일한 행만 중복으로 처리된다. 장르가 같아도 플랫폼이 다르면 별개의 행으로 간주한다.
5. WHERE 절에서의 LIKE & IN 적용 실습
5.1. LIKE(라이크) — 패턴 검색
1# 제목에 '황'이 포함된 웹툰 검색2cur.execute("SELECT title, author FROM webtoons WHERE title LIKE '%황%'")3rows = cur.fetchall()4print("=== '황' 포함 웹툰 ===")5for r in rows:6 print(f" {r[0]} - {r[1]}")1# 저자명이 두 글자인 작가 검색 (_는 글자 하나를 의미)2cur.execute("SELECT title, author FROM webtoons WHERE author LIKE '__'")3rows = cur.fetchall()4print("=== 두 글자 작가 ===")5for r in rows:6 print(f" {r[0]} - {r[1]}")코드 설명:
%— 0개 이상의 임의 문자_— 정확히 1개의 임의 문자LIKE '__'— 정확히 2글자인 값을 찾는다.
5.2. IN(인) — 여러 값 중 하나
1# 액션 또는 판타지 장르만 조회2cur.execute("""3 SELECT title, genre, score4 FROM webtoons5 WHERE genre IN ('액션', '판타지')6 ORDER BY score DESC7""")8rows = cur.fetchall()9print("=== 액션/판타지 웹툰 ===")10for r in rows:11 print(f" [{r[1]}] {r[0]} : {r[2]}")코드 설명:
- 5행:
IN ('액션', '판타지')— genre가 ‘액션’ 이거나 ‘판타지’인 행을 가져온다. IN은 여러 개의OR조건을 간결하게 표현한다.WHERE genre = '액션' OR genre = '판타지'와 동일하다.
5.3. NOT IN(낫 인) — 제외
1# 네이버웹툰이 아닌 플랫폼의 웹툰 조회2df = pd.read_sql(3 "SELECT title, platform FROM webtoons WHERE platform NOT IN ('네이버웹툰')",4 conn5)6print(df)코드 설명:
NOT IN— 괄호 안의 값 목록에 포함되지 않는 행을 가져온다.
6. 복합 조건 실전 실습
1# 완결된 판타지 또는 액션 웹툰 중 점수 9.0 이상2df = pd.read_sql("""3 SELECT title, genre, score, platform4 FROM webtoons5 WHERE complete = 16 AND genre IN ('판타지', '액션')7 AND score >= 9.08 ORDER BY score DESC9""", conn)10print("=== 완결 인기 웹툰 ===")11print(df)코드 설명:
- 5행:
complete = 1— 완결 웹툰만 선택한다. - 6행:
IN ('판타지', '액션')— 두 장르 중 하나인 것만 선택한다. - 7행:
score >= 9.0— 점수 9.0 이상인 것만 선택한다. - AND로 세 조건을 모두 만족하는 행만 가져온다.
7. 활용 Plus — 리액트 연동 관점
리액트 웹툰 앱에서 “장르 필터 + 정렬” 기능을 구현할 때, 파이썬 API는 아래와 같이 동작한다.
1def get_webtoons(genre=None, order="score"):2 base_sql = "SELECT title, genre, score, platform FROM webtoons"3 params = []4 if genre:5 base_sql += " WHERE genre = ?"6 params.append(genre)7 base_sql += f" ORDER BY {order} DESC"8 cur.execute(base_sql, params)9 return cur.fetchall()10
11# 사용 예12result = get_webtoons(genre="판타지", order="score")13for r in result:14 print(r)코드 설명:
- 1행: 장르와 정렬 기준을 함수 인자로 받아 동적으로 SQL을 구성한다.
- 4~6행: 장르가 지정된 경우에만 WHERE 절을 추가한다.
- 이 패턴이 실제 리액트 앱의 필터 기능 API 코드이다.
8. 문제풀기
조회 결과에서 중복된 값을 제거하고 고유한 값만 반환한다.
‘%공부%’: ‘공부’를 어느 위치에든 포함하는 값을 찾는다. ‘공부%’: ‘공부’로 시작하는 값만 찾는다.
여러 OR 조건을 간결하게 표현하기 위해서이다. WHERE genre=‘액션’ OR genre=‘판타지’를 WHERE genre IN (‘액션’,‘판타지’)로 단축할 수 있다.
먼저 genre를 알파벳/가나다 오름차순으로 정렬하고, 같은 genre 안에서는 score를 높은 순(내림차순)으로 다시 정렬한다.