행을 읽는 법: SELECT, WHERE, ORDER BY, LIMIT

대부분의 조회 쿼리는 SELECT, WHERE, ORDER BY, LIMIT 네 절로 읽을 수 있습니다. 각 절이 맡은 일을 예제로 하나씩 확인해 보겠습니다.

첫 쿼리

쿼리는 데이터베이스에 던지는 질문입니다. 어떤 행에서 어떤 컬럼이 필요한가? 가장 단순한 조회는 모든 컬럼을 뜻하는 SELECT *와 테이블을 지정하는 FROM으로 작성합니다.

1

-- Every column of every product. Run it with F9 or Ctrl/Cmd + Enter.
SELECT *
FROM products
LIMIT 20;
Planche에서 실행

결과 — 20행 중 처음 5행

idcategory_idnamedescriptionskupricecoststock_quantityweight_kgattributesis_activecreated_atupdated_at
116Glass Orchard (Paperback ed.)Glass Orchard (Paperback ed.) — built to last.SKU-00001913.72443.951796.18{"color":"green","warranty_months":12,"material":"fabric"}12024-01-13 07:13:522024-01-13 07:13:52
217Luma The GeneLuma The Gene — built to last.SKU-00002332.64161.72835.893{"color":"silver","warranty_months":24,"material":"steel"}12022-06-16 08:45:202022-06-16 08:45:20
321Quill HelmetQuill Helmet — designed for daily use.SKU-00003196.26118.253998.261{"color":"silver","warranty_months":24}12022-08-26 20:06:032022-08-26 20:06:03
416Kite Glass Orchard 3Kite Glass Orchard 3 — built to last.SKU-000041719.68845.912435.263{"color":"silver","warranty_months":24}02022-07-19 11:34:272022-07-19 11:34:27
517The Gene (3rd ed.)The Gene (3rd ed.) — a dependable everyday choice.SKU-00005122.869.53571.898{"color":"red","warranty_months":36,"material":"aluminium"}12022-05-21 10:53:402022-05-21 10:53:40

브라우저의 새 탭에서 Planche가 열리고, 샘플 데이터베이스가 로드된 채로 이 쿼리가 들어갑니다. 이 페이지의 다른 예제도 같은 탭을 다시 씁니다. F9를 누르기 전까지는 아무것도 실행되지 않습니다.

*는 모든 컬럼을, LIMIT 20은 최대 20행을 뜻합니다. products처럼 행이 많은 테이블은 구조만 확인할 때 전부 읽어 올 이유가 없습니다. 전송할 데이터와 화면에 그릴 양이 함께 늘어나기 때문입니다.

Planche에도 결과 행 제한이 있습니다(설정 › 안전장치 › 행 제한). 그래도 쿼리에 LIMIT을 적어 두는 편이 좋습니다. 앱의 제한은 브라우저를 위한 것이고, 서버가 읽는 데이터 양까지 줄여 주지는 않습니다.

필요한 컬럼만 고르기

SELECT *는 테이블을 살펴볼 때 편리합니다. 필요한 정보가 정해졌다면 컬럼 이름을 직접 나열하세요. 결과를 읽기 쉬워지고 전송해야 할 데이터도 줄어듭니다.

2

SELECT name, sku, price, stock_quantity
FROM products
LIMIT 20;
Planche에서 실행

결과 — 20행 중 처음 5행

nameskupricestock_quantity
Glass Orchard (Paperback ed.)SKU-00001913.72179
Luma The GeneSKU-00002332.6483
Quill HelmetSKU-00003196.26399
Kite Glass Orchard 3SKU-000041719.68243
The Gene (3rd ed.)SKU-00005122.8357

SELECT에 나열한 순서가 결과 컬럼의 순서가 됩니다. 테이블에 정의된 컬럼 순서와는 관계없습니다. 결과 컬럼 이름을 바꿀 때는 AS를 사용합니다.

WHERE로 행 거르기

SELECT가 컬럼을 고른다면 WHERE는 행을 고릅니다. 조건이 참인 행만 결과에 남깁니다.

3

SELECT name, price, stock_quantity
FROM products
WHERE price > 100
LIMIT 20;
Planche에서 실행

결과 — 20행 중 처음 5행

namepricestock_quantity
Lean Startup (Deluxe ed.)107.3784
Pixel Sofa108.187
Terra Pillow Pro113.670
Pulse LED Strip114.86480
Brief Answers (3rd ed.)117.96194

비교에는 =, <>(또는 !=), <, <=, >, >=를 사용합니다. 다만 NULL 비교에는 별도 규칙이 있습니다.

  • 같음은 = 하나입니다. ==가 아닙니다.
  • NULL은 무엇과도 같지 않습니다. NULL끼리도 같지 않습니다. 무게가 기록되지 않은 상품이 아무리 많아도 WHERE weight_kg = NULL은 한 행도 찾지 못합니다. IS NULL과 IS NOT NULL을 써야 합니다. 다음 레슨에서 제대로 다룹니다.

ORDER BY로 정렬하기

ORDER BY가 없으면 결과 순서는 보장되지 않습니다. 지금 보이는 순서가 데이터나 인덱스 변화 뒤에도 유지된다고 기대하면 안 됩니다.

4

SELECT name, price
FROM products
ORDER BY price DESC
LIMIT 20;
Planche에서 실행

결과 — 20행 중 처음 5행

nameprice
Glide GPS Watch Pro2484.4
Terra 3D Puzzle2481.77
Aria Castle Kit2479.41
Aria LED Strip Pro2463.41
Nova Brief Answers2445.49

DESC는 큰 값부터, ASC(기본값)는 작은 값부터 정렬합니다. ORDER BY price DESC와 LIMIT 20을 함께 쓰면 비싼 상품 20개를 가져옵니다. 먼저 전체를 가격순으로 정렬하고, 그 결과에서 20행을 고르는 순서입니다.

Planche에서는 결과 그리드의 컬럼 헤더를 눌러 정렬할 수도 있습니다. 오름차순, 내림차순, 정렬 해제 순으로 바뀌며 서버에서 다시 조회합니다. 이때 만들어지는 SQL을 보면 직접 작성한 쿼리도 확인할 수 있습니다.

정렬 키를 여러 개 쓰기

정렬 기준을 여러 개 지정하면, 앞 기준의 값이 같은 행을 뒤 기준으로 다시 정렬합니다.

5

SELECT category_id, name, price
FROM products
ORDER BY category_id, price DESC
LIMIT 30;
Planche에서 실행

결과 — 30행 중 처음 5행

category_idnameprice
2Aria Notebook2116.4
2Ember Laptop Plus2087.98
2Sol Notebook1982.34
2Sol Ultrabook1942.47
2Nimbus Ultrabook1933.06

이 쿼리는 카테고리 순으로 정렬한 뒤, 같은 카테고리 안에서는 가격이 높은 상품부터 보여 줍니다.

표현식과 별칭

SELECT에는 컬럼뿐 아니라 산술식이나 함수 호출도 넣을 수 있습니다. 행마다 계산된 값 하나가 만들어지고, AS로 그 결과에 이름을 붙일 수 있습니다.

6

SELECT name,
       price,
       cost,
       ROUND(price - cost, 2) AS margin
FROM products
WHERE is_active = 1
ORDER BY margin DESC
LIMIT 15;
Planche에서 실행

결과 — 15행 중 처음 5행

namepricecostmargin
Ember Tab Plus2412.93984.941427.99
Aria LED Strip Pro2463.411098.691364.72
Luma Denim Jacket Pro2357.59993.241364.35
Drift A Winter Letter2422.51082.431340.07
Nova Brief Answers2445.491108.091337.4

ROUND(price - cost, 2) AS margin은 테이블에 없는 값을 계산하고 결과 컬럼 이름을 margin으로 지정합니다. 이 별칭은 ORDER BY에서는 사용할 수 있지만 WHERE에서는 사용할 수 없습니다. 두 절이 평가되는 시점이 다르기 때문입니다.

FROM  ->  WHERE  ->  SELECT  ->  ORDER BY  ->  LIMIT

ORDER BY가 실행될 때는 SELECT가 이미 margin을 만들어둔 뒤입니다. 반면 WHERE가 실행될 때는 아직 없습니다. 그래서 WHERE margin > 50은 오류입니다. 표현식을 그대로 한 번 더 쓰거나, 이 쿼리를 다른 쿼리로 감싸야 합니다. 이 순서를 기억해두세요. WHERE가 그룹핑 전에 행을 거르고 HAVING이 그룹핑 후에 거르는 이유도 같은 순서로 설명됩니다. 두 레슨 뒤에 나옵니다.

여기까지로 할 수 있는 것

이 네 절만으로도 가장 비싼 상품 20개, 재고가 떨어진 상품, 판매 중인 상품 가운데 마진이 큰 상품처럼 한 테이블 안의 질문에 답할 수 있습니다. 고객과 주문처럼 두 테이블을 함께 읽는 질문에는 조인이 필요합니다.

예제의 숫자나 컬럼 이름을 바꿔 실행해 보세요. 결과가 어떻게 달라지는지 보면 각 절의 역할이 더 분명해집니다.

직접 해보기

  1. 아직 판매 중인 상품 중 가장 싼 열 개를, 이름과 가격만 보여주세요. (is_active가 1이면 판매 중입니다.)

    정답 보기

    정답 보기

    SELECT name, price
    FROM products
    WHERE is_active = 1
    ORDER BY price
    LIMIT 10;
    Planche에서 실행

    결과 — 10행 중 처음 5행

    nameprice
    Clean Code (2nd ed.)6.89
    Nimbus Desk Max7.21
    Drift Castle Kit Max17.35
    Pixel Laptop18.46
    Terra Dumbbell Set19.8

    절 셋이 각각 하나씩 일합니다. WHERE가 판매 중이 아닌 상품을 빼고, ORDER BY price가 싼 것부터 놓고(오름차순이 기본이라 키워드가 필요 없습니다), LIMIT 10이 거기서 멈춥니다.

  2. 상품마다 재고 금액이 얼마인가요? 이름, 수량, 그리고 가격 × 수량을 소수점 두 자리로 반올림해서 큰 것부터 보여주세요.

    정답 보기

    정답 보기

    SELECT name,
           stock_quantity,
           ROUND(price * stock_quantity, 2) AS stock_value
    FROM products
    ORDER BY stock_value DESC
    LIMIT 10;
    Planche에서 실행

    결과 — 10행 중 처음 5행

    namestock_quantitystock_value
    Luma Boots4921042454.52
    Glide GPS Watch Pro4141028541.6
    Brief Answers (Deluxe ed.)434988448.02
    Brief Answers (Hardcover ed.)413980879.13
    Vega Field Watch464975221.28

    세 번째 컬럼은 테이블 어디에도 없습니다. AS stock_value가 이름을 붙이고, ORDER BY는 SELECT 다음에 실행되므로 그 이름으로 정렬할 수 있습니다.