SQL 기초 — SELECT 부터 서브쿼리까지
SELECT·WHERE·JOIN·집계·서브쿼리·CASE 를 익힙니다. SQL 이 처음이라면 여기서 시작하세요. 연습 데이터는 실제 SAP 테이블입니다.
1. SELECT 와 WHERE — 필요한 열과 행만 고르기
SELECT 는 어떤 열을, FROM 은 어느 테이블에서, WHERE 는 어떤 행만 가져올지 정합니다. SAP 데이터셋은 자재(MARA), 고객(KNA1), 공급업체(LFA1) 같은 마스터부터 읽습니다.
SELECT MATNR, MTART, MEINS
FROM MARA
WHERE MTART IN ('FERT', 'HAUN')
AND LVORM <> 'X';
- SAP 날짜(DATS)는
'YYYYMMDD'형식의 문자열입니다. 기간은ERDAT BETWEEN '20250101' AND '20251231'처럼 문자열로 비교합니다. - 번호 필드는 앞자리 0을 포함해 저장됩니다(
KUNNR = '0000100001'). 화면처럼 0을 지우려면LTRIM(KUNNR, '0'). - 문자 필드의 빈 값
''과 NULL 은 다릅니다. 미설정 값은 빈 문자열인 경우가 많으니IS NULL과= ''를 구분하세요. - 삭제 표시(
LVORM = 'X'), 오더 차단(AUFSD) 같은 플래그는<> 'X'로 제외합니다.
문제
2. 정렬과 상위 N개
ORDER BY 로 결과 순서를 정합니다. 기본은 오름차순(ASC), 큰 값부터는 DESC 입니다.
SELECT MATNR, STPRS
FROM MBEW
WHERE BWKEY = '1000'
ORDER BY STPRS DESC, MATNR
LIMIT 5;
- 정렬 기준을 여러 개 주면 앞의 기준이 같은 행끼리 다음 기준으로 정렬합니다. 금액·수량처럼 동점이 흔한 열에는 행 번호 같은 두 번째 기준을 붙여야 결과가 흔들리지 않습니다.
- SAP HANA 에서 상위 N개는
LIMIT n또는SELECT TOP n …으로 가져옵니다. 페이지 이동은LIMIT n OFFSET m. - NULL 의 정렬 위치는 DB 기본값에 따라 다릅니다. 필요하면
NULLS FIRST/NULLS LAST를 명시하세요.
문제
3. 문자열·날짜 함수
SAP 의 날짜(DATS)와 번호 필드는 문자열이라 함수로 다듬는 일이 많습니다.
| 목적 | HANA 함수 |
|---|---|
| 일부 자르기 | LEFT(s, n), SUBSTRING(s, 시작, 길이) |
| 앞자리 0 지우기 | LTRIM(KUNNR, '0') |
| 자리 채우기 | LPAD(s, n, '0') |
| 문자 → 날짜 | TO_DATE(s, 'YYYYMMDD') |
| 날짜 계산 | ADD_DAYS(d, n), ADD_MONTHS(d, n) |
| 날짜 차이 | DAYS_BETWEEN(시작, 끝) |
| 날짜 → 문자 | TO_VARCHAR(d, 'YYYY-MM') |
SELECT VBELN,
TO_DATE(ERDAT, 'YYYYMMDD') AS ORDER_DATE,
ADD_DAYS(TO_DATE(ERDAT, 'YYYYMMDD'), 30) AS DUE_DATE
FROM VBAK
WHERE ERDAT >= '20250101';
DAYS_BETWEEN(a, b)는 b − a 입니다. 지급 기한이 지난 일수는DAYS_BETWEEN(기한, 기준일)로 양수가 됩니다.- 기간 조건은 날짜로 바꾼 뒤 비교하면 월·연 경계를 다루기 쉽습니다.
문제
4. 집계 함수 — COUNT · SUM · AVG · MIN · MAX
집계 함수는 여러 행을 한 값으로 줄입니다. GROUP BY 가 없으면 전체가 한 그룹입니다.
SELECT COUNT(*) AS DOC_COUNT,
COUNT(DISTINCT MATNR) AS MATERIALS,
SUM(NETWR) AS TOTAL_AMOUNT,
AVG(NETWR) AS AVG_AMOUNT
FROM EKPO;
COUNT(*)는 모든 행을,COUNT(컬럼)은 그 컬럼이 NULL 이 아닌 행만 셉니다.COUNT(DISTINCT 컬럼)은 서로 다른 값의 개수입니다. 중복 없는 목록 자체는SELECT DISTINCT.- SUM·AVG 도 NULL 은 빼고 계산합니다. 행이 하나도 없으면 SUM 은 NULL, COUNT 는 0 입니다.
- 결과 열에는
AS로 이름을 붙이세요. 문제의 결과 명세가 그 이름을 기준으로 채점됩니다.
문제
5. GROUP BY 와 HAVING — 묶어서 집계하기
GROUP BY 는 같은 값을 가진 행을 묶고, 묶음마다 집계합니다.
SELECT KUNNR, COUNT(*) AS ORDER_COUNT, SUM(NETWR) AS SALES
FROM VBAK
WHERE AUART = 'OR'
GROUP BY KUNNR
HAVING SUM(NETWR) >= 1000000;
- SELECT 에는 묶는 기준 컬럼과 집계 함수만 올 수 있습니다. GROUP BY 에 없는 컬럼을 그냥 쓰면 오류입니다.
WHERE는 묶기 전에 행을 거르고,HAVING은 묶은 뒤 그룹을 거릅니다. 집계 결과로 거를 때는 HAVING 입니다.- 묶는 기준이 여러 개면 그 조합마다 한 행이 나옵니다. 기간·플랜트·통화처럼 업무 단위를 먼저 정하세요.
문제
6. INNER JOIN — 테이블 잇기
JOIN 은 두 테이블을 공통 키로 잇습니다. SAP 테이블 대부분은 헤더-품목, 마스터-트랜잭션 관계라 JOIN 이 가장 중요한 문법입니다.
SELECT K.EBELN, L.NAME1, P.EBELP, P.MATNR, P.NETWR
FROM EKKO K
JOIN EKPO P ON P.EBELN = K.EBELN
JOIN LFA1 L ON L.LIFNR = K.LIFNR
WHERE K.BUKRS = '1000';
INNER JOIN(그냥JOIN)은 양쪽에 짝이 있는 행만 남깁니다.- 테이블 별칭(K, P, L)을 붙이면 컬럼이 어느 테이블 것인지 분명해집니다.
- 키 전체로 이어야 합니다. 헤더-품목은 문서 번호, 품목끼리는 문서 번호 + 품목 번호처럼 조합 키가 흔합니다.
- 헤더 금액(VBAK.NETWR)을 품목과 조인한 뒤 SUM 하면 품목 수만큼 여러 번 더해집니다. 금액은 한쪽 기준으로만 집계하세요.
문제
7. LEFT JOIN 과 NULL
LEFT JOIN 은 왼쪽 테이블의 행을 모두 남기고, 오른쪽에 짝이 없으면 NULL 로 채웁니다. "없는 것"까지 보고서에 넣을 때 씁니다.
SELECT K.KUNNR, K.NAME1, COUNT(V.VBELN) AS ORDER_COUNT
FROM KNA1 K
LEFT JOIN VBAK V
ON V.KUNNR = K.KUNNR
AND V.AUART = 'OR'
WHERE K.LAND1 = 'KR'
GROUP BY K.KUNNR, K.NAME1;
COUNT(V.VBELN)은 짝이 없는 고객을 0 으로 셉니다.COUNT(*)를 쓰면 1 이 되니 주의하세요.- 짝이 없는 행만 찾을 때는
LEFT JOIN … WHERE 오른쪽키 IS NULL을 씁니다. - 필터 위치가 중요합니다. 오른쪽 테이블 조건을 WHERE 에 쓰면 NULL 행이 걸러져 INNER JOIN 처럼 됩니다. 조건은
ON절에 두세요. - NULL 을 다른 값으로 바꿀 때는
COALESCE(a, b)또는 HANA 의IFNULL(a, b).
문제
8. 서브쿼리 — 쿼리 안의 쿼리
다른 쿼리의 결과를 조건이나 값, 또는 임시 테이블처럼 씁니다.
SELECT KUNNR, NETWR
FROM VBAK
WHERE NETWR > (SELECT AVG(NETWR) FROM VBAK WHERE AUART = 'OR');
- 값 하나를 돌려주면 비교 연산자와, 여러 값이면
IN (SELECT …), 존재 여부만 보면EXISTS (SELECT …)와 씁니다. - FROM 절에 쓰는 서브쿼리는 파생 테이블입니다. 먼저 집계한 결과를 다시 필터·조인할 수 있습니다.
- 바깥 행을 참조하는 상관 서브쿼리는 바깥 행마다 다시 계산됩니다.
NOT IN (서브쿼리)결과에 NULL 이 섞이면 어떤 행도 선택되지 않습니다. "없음"을 찾을 때는NOT EXISTS가 안전합니다.
문제
9. CASE 와 조건 분기
CASE 는 조건에 따라 다른 값을 만듭니다. 구간 분류와 조건부 집계에 자주 씁니다.
SELECT KUNNR,
SUM(CASE WHEN AUART = 'OR' THEN NETWR ELSE 0 END) AS ORDER_AMOUNT,
SUM(CASE WHEN AUART = 'RE' THEN NETWR ELSE 0 END) AS RETURN_AMOUNT,
CASE WHEN SUM(NETWR) >= 100000000 THEN '대형'
WHEN SUM(NETWR) >= 10000000 THEN '중형'
ELSE '소형' END AS CUSTOMER_BAND
FROM VBAK
GROUP BY KUNNR;
- 조건은 위에서부터 검사하고 처음 맞는 것을 씁니다. 아무것도 안 맞고 ELSE 도 없으면 NULL 입니다.
SUM(CASE …)로 조건별 합계를 한 행에 나란히 놓는 것이 피벗의 기본입니다.- HANA 의
MAP(값, 'A', '가', 'B', '나', '기타')는 단순 값 치환을 짧게 씁니다. - NULL 비교는
= NULL이 아니라IS NULL입니다. 기본값은COALESCE/IFNULL로 채웁니다.