What I Do

SQL SELECT 문 기초: SELECT·FROM 으로 원하는 열만 꺼내기

8분 읽기

SQL SELECT 문은 표에서 보고 싶은 열을 골라 꺼내는 문장입니다. SELECT·FROM 기본형, SELECT * 를 피하는 이유, AS 로 별칭 짓기, DISTINCT 로 중복 빼기, 계산 열 만들기를 주문 표 예시 쿼리로 따라 해 봅니다.

SQL SELECT 문 기초: SELECT·FROM 으로 원하는 열만 꺼내기

SQL SELECT 문은 표에서 보고 싶은 열을 골라 꺼내는 문장입니다. SELECT 뒤에 열 이름을, FROM 뒤에 표 이름을 적으면 되는데요, 여기에 별칭(AS)과 중복 빼기(DISTINCT), 계산 열까지 알면 원본 표를 건드리지 않고도 보고서에 필요한 모양을 꽤 많이 만들 수 있습니다. 저도 SQL 을 처음 배우면서 「일단 SELECT * 로 다 꺼내 놓고 보면 되지 않나?」라고 생각했는데요, 이번 글에서는 SELECT·FROM 의 기본형부터 * 를 아껴 써야 하는 이유, 열 이름을 바꾸고 계산하는 법까지 예시 표로 직접 따라 해 보겠습니다. 쿼리는 BigQuery(GoogleSQL) 문법으로 적었습니다. 지난 글: SQL 이란? 명령어 종류와 쿼리가 실행되는 순서

SQL 기초 시리즈 6/12 · 전체 커리큘럼

오늘 배울 개념

지난 글에서 SELECT 문은 FROM 부터 읽힌다고 했죠. 오늘은 그 두 절만 떼어 보는데요, FROM 은 「어느 표에서」, **SELECT 는 「어떤 열을 보여 줄지」**를 정합니다. BigQuery 쿼리 문법 문서도 SELECT 목록을 「쿼리가 돌려줄 열을 정하는 곳」이라고 설명합니다. 엑셀로 치면 열 숨기기와 비슷합니다. 주문 시트에 열이 열 개 있어도 보고서에는 날짜·채널·금액 세 열만 보이면 충분할 때가 많은데요, 엑셀은 나머지 열을 숨기거나 지우지만 SQL 은 원본 표는 그대로 두고 고른 열만 담은 새 결과 표를 돌려줍니다. 원본을 실수로 망가뜨릴 걱정이 없는 셈이죠.

따라 해 보기: SQL SELECT 문으로 열 고르기

문구점 주문 표 shop.orders 를 쓰겠습니다(가상 데이터). shop 은 데이터셋 이름, orders 는 표 이름인데요, BigQuery 문법 문서의 예시처럼 표 이름 앞에 데이터셋을 붙여 데이터셋.표 로 적습니다.

orders

order_idorder_datechannelproductunit_pricequantity
12026-11-02검색광고볼펜15004
22026-11-02SNS노트30002
32026-11-03검색광고노트30001
42026-11-03이메일볼펜150010
52026-11-04SNS노트30003
62026-11-05검색광고형광펜20005

1. 필요한 열만 꺼내기: 열 이름을 쉼표로 이어 적고, FROM 뒤에 표를 적습니다.

SELECT order_id, channel, product
FROM shop.orders;
order_idchannelproduct
1검색광고볼펜
2SNS노트
3검색광고노트
4이메일볼펜
5SNS노트
6검색광고형광펜

행은 6개 그대로이고 열만 세 개로 줄었습니다. 결과 표의 열 순서는 원본이 아니라 SELECT 에 적은 순서를 따르는데요, 위 결과의 행 순서는 보기 좋게 원본 순서대로 적었을 뿐이고 ORDER BY 가 없으면 행 순서는 정해져 있지 않다는 점을 지난 글에서 짚었죠.

주문 표 여섯 열 가운데 order_id·channel·product 세 열만 골라 결과 표로 꺼내는 SQL SELECT 문 그림 개념 그림: FROM 으로 표를 정하고, SELECT 로 고른 열만 새 결과 표에 담깁니다

2. 계산 열과 별칭(AS): SELECT 목록에는 열 이름뿐 아니라 계산식도 쓸 수 있습니다. 단가와 수량을 곱해 주문 금액을 만들고 AS 로 이름을 붙여 보겠습니다.

SELECT
  order_id,
  product,
  unit_price * quantity AS amount
FROM shop.orders;
order_idproductamount
1볼펜6000
2노트6000
3노트3000
4볼펜15000
5노트9000
6형광펜10000

amount 는 원본 표에 없는 열인데요, 행마다 계산해 결과에만 붙은 열이라 원본은 바뀌지 않습니다. BigQuery 연산자 문서의 결과 타입 표를 보면 두 열이 INT64(정수)일 때 곱하면 INT64 가 되고, INT64 끼리 나누면 FLOAT64 가 되는데요, 금액을 나눌 때 소수점이 붙어 나오는 이유가 여기에 있습니다.

unit_price 와 quantity 두 열을 곱한 값이 AS amount 라는 이름표를 단 새 열로 결과 표에 붙는 과정을 보여 준 그림 개념 그림: 계산 열에 AS 로 이름표를 붙여야 뒤에서 그 이름으로 부를 수 있습니다

3. DISTINCT 로 중복 빼기: 「어떤 채널에서 주문이 들어왔나」만 알고 싶을 때는 DISTINCT 를 씁니다. 문법 문서에 따르면 SELECT DISTINCT 는 중복된 행을 버리고 남은 행만 돌려줍니다.

SELECT DISTINCT channel
FROM shop.orders;
channel
검색광고
SNS
이메일

여기서 중복 판단은 SELECT 에 적은 열 전체의 조합으로 합니다. SELECT DISTINCT channel, product 로 바꾸면 (SNS, 노트) 조합만 2번·5번 주문에서 겹쳐 한 줄로 합쳐지고, 나머지 다섯 조합이 남습니다.

channelproduct
검색광고볼펜
SNS노트
검색광고노트
이메일볼펜
검색광고형광펜

channel 열 여섯 행이 DISTINCT 를 거쳐 검색광고·SNS·이메일 세 행으로 줄어드는 모습을 체로 거르는 장면처럼 그린 그림 개념 그림: DISTINCT 는 SELECT 에 적은 열 조합이 같은 행을 한 줄만 남깁니다

4. FROM 없이 계산만 하기: 문법 문서의 SELECT 구문에서 FROM 은 대괄호로 묶인 「생략 가능한 절」인데요, 그래서 표 없이 계산기처럼 쓸 수도 있습니다.

SELECT 1500 * 4 AS amount;
amount
6000

계산식이 맞는지 표에 넣기 전에 따로 확인해 볼 때 쓸모가 있습니다. 다만 PostgreSQL SELECT 문서에 따르면 다른 DBMS 중에는 FROM 을 생략하지 못하고 한 행짜리 임시 표를 따로 둬야 하는 제품도 있습니다. 위 결과 표의 값은 모두 예시 표가 작아 손으로 계산해 맞춘 값입니다.

SELECT * 는 언제 써도 되고 언제 피해야 할까요?

SELECT * 는 「보이는 모든 열」을 꺼내는 별표(select star) 문법입니다. 처음 보는 표의 모양을 확인할 때는 편하지만, 보고서에 들어갈 쿼리라면 열을 직접 적는 편이 안전한데요, 이유는 두 문서에서 찾을 수 있습니다.

  • 표가 바뀌면 결과도 따라 바뀝니다: Microsoft Learn 의 SQL 입문 과정은 SELECT * 가 빠른 테스트에는 괜찮지만, 표에 열이 추가되거나 순서가 바뀌면 그대로 결과에 반영돼 그 쿼리를 쓰는 보고서가 예상과 다른 결과를 받을 수 있다고 설명합니다.
  • 필요 없는 열까지 읽습니다: 같은 과정은 필요 없는 데이터를 돌려주면 쿼리가 느려질 수 있다고 적고, BigQuery 성능 권장사항 문서도 「필요한 열만 조회하라」며 불필요한 열을 읽으면 그만큼 입출력이 낭비된다고 안내합니다. 같은 문서에 따르면 SELECT * 에 LIMIT 를 붙여도 읽는 데이터 양은 줄지 않습니다.

BigQuery 에는 「거의 다 필요한데 몇 개만 빼고 싶을 때」 쓰는 SELECT * EXCEPT 도 있습니다. 문법 문서 설명대로 괄호 안에 적은 열만 결과에서 빠지는데요, 아래 쿼리는 order_date 를 뺀 다섯 열을 돌려줍니다.

SELECT * EXCEPT (order_date)
FROM shop.orders;

세 방식을 나란히 놓으면 이렇습니다.

방식결과 열표에 열이 늘면이럴 때
열 이름을 직접 적기적은 열만, 적은 순서대로결과는 그대로보고서·대시보드에 들어갈 쿼리
SELECT *모든 열새 열이 결과에 끼어든다처음 보는 표의 모양 확인
SELECT * EXCEPT (...)뺀 열을 제외한 모두새 열이 결과에 끼어든다열이 많고 몇 개만 빼면 될 때

EXCEPT 도 별표를 쓰는 방식이라 표가 바뀌면 결과가 같이 바뀐다는 점은 * 와 같습니다. 그래서 저는 「한 번 보고 버릴 쿼리면 별표, 다시 쓸 쿼리면 열 이름」을 기준으로 삼으려 하는데요, 그렇다면 실무 쿼리에서는 열을 어떤 순서로 골라 적으면 될까요?

실무에서는 어떻게 쓸까요? 주간 보고용 열 뽑기

매주 월요일 채널별 주문 내역을 보고하는 담당자를 떠올려 보겠습니다. 보고서에 필요한 것은 주문일·채널·상품·금액 네 칸뿐인데요, 원본 표에는 단가와 수량이 따로 있고 금액 열은 없습니다.

  1. FROM 부터 정합니다: 어느 표에 원하는 값이 있는지 확인하고 FROM shop.orders 를 적습니다.
  2. 보고서 열 순서대로 SELECT 를 씁니다: order_date, channel, product 를 보고서 칸 순서대로 적습니다.
  3. 없는 열은 계산해 만듭니다: unit_price * quantity AS amount 로 금액 열을 붙입니다.
  4. 이름은 보고서와 맞춥니다: 받는 사람이 알아보기 쉽게 별칭을 정하는데요, 공백이나 하이픈이 든 이름을 쓰려면 어휘 구조 문서대로 백틱 기호로 감싸야 해서, 영문·숫자·밑줄로 짓는 편이 덜 번거롭습니다.
SELECT
  order_date,
  channel,
  product,
  unit_price * quantity AS amount  -- 금액 = 단가 × 수량
FROM shop.orders;

-- 뒤는 쿼리가 무시하는 주석인데요, 어휘 구조 문서에 따르면 -- 와 #, /* */ 를 주석으로 쓸 수 있습니다. 계산 열 옆에 계산 근거를 적어 두면 다음 주의 내가 덜 헷갈리겠죠. 다음 회차에서 WHERE 로 「지난주 주문만」 거르는 조건을 붙이면 이 쿼리가 그대로 주간 보고 쿼리가 됩니다. 다른 DBMS 에서는 문자열을 이어 붙이는 방식이 다른데요, BigQuery 는 || 연산자(또는 CONCAT 함수)를 쓰고, T-SQL 문자열 연결 문서에 따르면 SQL Server 는 + 로 문자열을 잇습니다.

연습 문제

1. (쉬움) shop.orders 에서 주문 번호와 주문일만 꺼내는 쿼리를 써 보세요.

정답 보기
SELECT order_id, order_date
FROM shop.orders;

6행, 2열(order_id, order_date)이 나옵니다. 열 사이 쉼표와 FROM 뒤 표 이름만 맞으면 됩니다.

2. (보통) 이 표에서 팔린 상품의 종류만 중복 없이 보는 쿼리를 쓰고, 결과가 몇 행인지 답해 보세요.

정답 보기
SELECT DISTINCT product
FROM shop.orders;

볼펜(1·4번), 노트(2·3·5번), 형광펜(6번)이라 3행입니다. DISTINCT 없이 쓰면 6행이 그대로 나옵니다.

3. (보통) 아래 쿼리를 실행하면 결과 열은 몇 개이고, 열 이름은 무엇일까요?

SELECT order_id product, quantity
FROM shop.orders;
정답 보기

열은 2개이고 이름은 product, quantity 입니다. order_id 와 product 사이에 쉼표가 없어서, AS 를 생략한 별칭으로 읽혀 「order_id 값을 product 라는 이름으로 보여 달라」는 뜻이 되기 때문입니다. 그래서 product 열에는 상품명이 아니라 1부터 6까지의 주문 번호가 들어 있습니다.

자주 하는 실수

  • 쉼표를 빠뜨려 열이 별칭이 됩니다: 문법 문서의 SELECT 항목 구문은 expression [ [ AS ] alias ] 로, AS 를 생략해도 별칭이 됩니다. 연습 문제 3번처럼 오류 없이 엉뚱한 결과가 나와서 더 알아채기 어려운데요, 별칭에는 늘 AS 를 적고 열은 한 줄에 하나씩 쓰면 빠진 쉼표가 눈에 잘 띕니다.
  • 계산 열에 이름을 안 붙입니다: 문법 문서에 따르면 channel 처럼 열 이름만 쓰면 그 이름이 그대로 별칭이 되지만, unit_price * quantity 같은 계산식은 별칭이 없으면 이름 없는 열이 되어 쿼리 안에서 이름으로 부를 수 없습니다. 결과 화면에 임시 이름이 보이더라도 그 이름은 별칭처럼 쓸 수 없다고 문서는 적고 있죠.
  • 열 이름을 따옴표로 감쌉니다: BigQuery 에서 작은따옴표·큰따옴표는 문자열 값이고, 이름을 감싸는 것은 백틱입니다. SELECT 'channel' 은 channel 열이 아니라 「channel」이라는 글자를 행마다 돌려주는데요, 어휘 구조 문서에 따르면 FROM 처럼 예약어와 같은 이름이나 숫자로 시작하는 이름도 백틱으로 감싸야 합니다.

키워드와 열 이름은 대소문자를 구분하지 않아 select channel from shop.orders 도 돌아가지만, 같은 문서에 따르면 데이터셋·표 이름은 (따로 설정하지 않는 한) 대소문자를 구분합니다. 이 시리즈에서 키워드를 대문자로 쓰는 것은 읽기 쉽게 하려는 관례입니다.

마치며

SQL SELECT 문은 FROM 으로 표를 정하고 SELECT 로 열을 고르는 데서 시작하고, 여기에 AS 로 이름을 붙이고 DISTINCT 로 중복을 빼고 계산 열을 더하면 원본을 건드리지 않고 보고서 모양을 만들 수 있습니다. SELECT * 는 표를 처음 볼 때만 쓰고, 다시 쓸 쿼리에는 필요한 열을 직접 적어 두시길 권합니다. 저도 시리즈를 따라가며 공부하고 있으니 전체 커리큘럼을 참고해 주세요. 다음 글에서는 WHERE 로 조건에 맞는 행만 거르는 법을 다룹니다.

자주 묻는 질문

SQL SELECT 문은 어떻게 쓰나요?
SELECT 뒤에 보고 싶은 열 이름을 쉼표로 이어 적고, FROM 뒤에 표 이름을 적습니다. 예를 들어 SELECT order_id, channel FROM shop.orders; 는 주문 표에서 두 열만 꺼냅니다. 결과는 새 표로 돌아오고 원본 표는 바뀌지 않습니다.
SELECT * 를 쓰면 안 되나요?
처음 보는 표의 모양을 확인할 때는 괜찮습니다. 다만 표에 열이 추가되거나 순서가 바뀌면 결과도 따라 바뀌고, 필요 없는 열까지 읽어 쿼리가 느려질 수 있어서 보고서처럼 다시 쓸 쿼리에는 열 이름을 직접 적는 편이 안전합니다. BigQuery 에서는 SELECT * 에 LIMIT 를 붙여도 읽는 데이터 양이 줄지 않습니다.
SQL DISTINCT 는 어떤 기준으로 중복을 빼나요?
SELECT 에 적은 열 전체의 조합이 같은 행을 중복으로 보고 한 줄만 남깁니다. SELECT DISTINCT channel 은 채널 종류만, SELECT DISTINCT channel, product 는 채널과 상품 조합의 종류를 돌려줍니다.

관련 글 더 보기