SQL : 기본 SQL 문법

Skele·2025년 5월 13일

SQL

목록 보기
4/11
post-thumbnail

1. SELECT 문의 기본 구조

SELECT 문은 데이터베이스에서 데이터를 조회하는 가장 기본적인 명령어다. 내부 파싱 순서는 FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY 순으로 실행된다.

SELECT [DISTINCT] 컬럼명 [AS 별칭], 컬럼명 [별칭], 표현식, ...
FROM 테이블명 [별칭]
[WHERE 조건식]
[GROUP BY 그룹화할_컬럼명]
[HAVING 그룹_조건식]
[ORDER BY 정렬할_컬럼명 [ASC|DESC]]

SELECT 절

  • 조회할 컬럼을 지정한다
  • * 사용 시 모든 컬럼 조회
  • 별칭(Alias) 사용 가능: 컬럼명 AS 별칭 또는 컬럼명 별칭
  • 별칭에 공백이나 특수문자가 있을 경우 쌍따옴표로 묶어야 함
  • 표현식(연산식, 함수식 등) 사용 가능
SELECT empno, ename AS 이름, sal * 1.1 "인상된 급여"
FROM emp;

FROM 절

  • 데이터를 가져올 테이블 지정
  • 테이블 별칭 사용 가능(조인 시 특히 유용)
  • ORACLE에서는 FROM 절 생략 불가(의미상 필요 없을 경우 DUAL 테이블 사용)
  • SQL Server에서는 필요 없을 경우 생략 가능
SELECT sysdate FROM dual;  -- ORACLE에서 현재 날짜 조회
SELECT getdate();  -- SQL Server에서 현재 날짜 조회(FROM 절 생략)

2. WHERE 절

데이터를 필터링하는 조건을 지정한다. 다양한 연산자를 사용할 수 있다.

비교 연산자와 논리 연산자

  • 비교: =, >, >=, <, <=, <> (또는 !=) 등
  • 논리: AND, OR, NOT
-- 부서번호가 10이거나 20이면서 급여가 2000 이상인 직원
SELECT empno, ename, deptno, sal
FROM emp
WHERE (deptno = 10 OR deptno = 20) AND sal >= 2000;

특수 연산자

  • IN: 여러 값 중 일치하는 것이 있는지 확인
-- 부서번호가 10, 20, 30 중 하나인 직원
SELECT empno, ename, deptno
FROM emp
WHERE deptno IN (10, 20, 30);
  • BETWEEN A AND B: A와 B 사이의 값인지 확인
-- 급여가 2000에서 3000 사이인 직원
SELECT empno, ename, sal
FROM emp
WHERE sal BETWEEN 2000 AND 3000;
  • LIKE: 패턴 매칭 (%, _ 와일드카드 사용)
-- 이름이 S로 시작하는 직원
SELECT empno, ename FROM emp WHERE ename LIKE 'S%';

-- 이름의 두 번째 글자가 A인 직원
SELECT empno, ename FROM emp WHERE ename LIKE '_A%';
  • IS NULL / IS NOT NULL: NULL 값 확인
-- 커미션이 NULL인 직원
SELECT empno, ename, comm
FROM emp
WHERE comm IS NULL;

NULL 처리 주의사항

  • NULL은 알 수 없는 값을 의미하며, 0이나 빈 문자열('')과 다름
  • NULL과의 모든 연산 결과는 NULL
  • NULL 비교 시 = 연산자 사용 불가, IS NULL/IS NOT NULL 사용해야 함
  • 그룹 함수(SUM, AVG, MIN, MAX 등)는 NULL을 제외하고 연산
-- NULL 처리 예시
SELECT ename, sal, comm, sal + comm "계산결과"
FROM emp;  -- comm이 NULL인 행은 계산결과도 NULL

-- NULL 처리를 위한 NVL/COALESCE 함수 사용
SELECT ename, sal, comm, sal + NVL(comm, 0) "계산결과"
FROM emp;  -- NULL을 0으로 변환하여 계산

3. ORDER BY 절

결과를 정렬할 때 사용한다. SELECT 절의 마지막에 위치하며, 내부적으로도 가장 마지막에 수행된다.

정렬 방식

  • 오름차순: ASC(기본값, 생략 가능)
  • 내림차순: DESC
  • 여러 컬럼으로 정렬 가능(순서대로 우선순위 적용)
  • SELECT 절에서 정의한 별칭 사용 가능
  • SELECT 절에 선언된 순서대로의 숫자 사용 가능
-- 부서번호 오름차순, 같은 부서 내에서는 급여 내림차순 정렬
SELECT empno, ename, deptno, sal
FROM emp
ORDER BY deptno, sal DESC;

-- 별칭으로 정렬
SELECT empno, ename, sal*12 AS 연봉
FROM emp
ORDER BY 연봉 DESC;

-- 컬럼 위치로 정렬
SELECT empno, ename, deptno, sal
FROM emp
ORDER BY 3, 4 DESC;  -- 3번째 컬럼(deptno) 오름차순, 4번째 컬럼(sal) 내림차순

NULL 정렬

  • ORACLE: NULL은 기본적으로 가장 큰 값으로 취급(오름차순 정렬 시 마지막에 위치)
    • NULLS FIRST / NULLS LAST 옵션으로 위치 지정 가능
  • SQL Server: NULL은 기본적으로 가장 작은 값으로 취급(오름차순 정렬 시 처음에 위치)
-- ORACLE에서 NULL 정렬 제어
SELECT ename, comm
FROM emp
ORDER BY comm NULLS FIRST;  -- NULL을 맨 앞에 정렬

4. GROUP BY와 HAVING 절

GROUP BY 절

데이터를 그룹화하여 집계 함수를 적용할 때 사용한다.

  • 같은 값을 가진 행들을 하나의 그룹으로 묶음
  • 주로 집계 함수(SUM, AVG, MAX, MIN, COUNT 등)와 함께 사용
  • SELECT 절에는 GROUP BY에 명시된 컬럼과 집계 함수만 사용 가능
-- 부서별 평균 급여
SELECT deptno, AVG(sal) 평균급여
FROM emp
GROUP BY deptno;

-- 부서별, 직무별 직원 수와 평균 급여
SELECT deptno, job, COUNT(*) 직원수, AVG(sal) 평균급여
FROM emp
GROUP BY deptno, job;

HAVING 절

GROUP BY로 생성된 그룹에 조건을 적용할 때 사용한다.

  • WHERE는 개별 행에 조건을 적용하지만, HAVING은 그룹화된 결과에 조건을 적용
  • 집계 함수를 조건으로 사용할 때는 WHERE 대신 HAVING 사용
-- 평균 급여가 2000 이상인 부서만 조회
SELECT deptno, AVG(sal) 평균급여
FROM emp
GROUP BY deptno
HAVING AVG(sal) >= 2000;

-- 직원이 3명 이상인 부서의 최대 급여
SELECT deptno, COUNT(*) 직원수, MAX(sal) 최대급여
FROM emp
GROUP BY deptno
HAVING COUNT(*) >= 3;

5. 주요 SQL 함수

SQL에서는 다양한 내장 함수를 제공하여 데이터 처리를 돕는다.

문자 함수

문자 변환 함수

  • UPPER(문자열): 대문자로 변환
  • LOWER(문자열): 소문자로 변환
  • INITCAP(문자열): 각 단어의 첫 글자만 대문자로 변환 (ORACLE)
SELECT UPPER('hello'), LOWER('WORLD'), INITCAP('hello world') FROM dual;
-- 결과: HELLO, world, Hello World

문자 추출/조작 함수

  • LENGTH(문자열) / LEN(문자열): 문자열 길이 반환
  • SUBSTR(문자열, 시작위치, 길이) / SUBSTRING(문자열, 시작위치, 길이): 부분 문자열 추출
  • INSTR(문자열, 찾을문자열, [시작위치, [발생횟수]]) / CHARINDEX(찾을문자열, 문자열, [시작위치]): 문자열 위치 찾기
SELECT LENGTH('hello world'), SUBSTR('hello world', 1, 5), INSTR('hello world', 'o') FROM dual;
-- 결과: 11, hello, 5

문자 제거/치환 함수

  • TRIM([LEADING|TRAILING|BOTH] [제거할문자] FROM 문자열): 문자열 앞/뒤의 공백 또는 특정 문자 제거
  • LTRIM(문자열, [제거할문자들]): 왼쪽에서 문자 제거
  • RTRIM(문자열, [제거할문자들]): 오른쪽에서 문자 제거
  • REPLACE(문자열, 찾을문자열, 대체문자열): 문자열 치환
SELECT TRIM(' hello '), LTRIM('xxxhello', 'x'), REPLACE('hello world', 'world', 'SQL') FROM dual;
-- 결과: hello, hello, hello SQL

문자 결합 함수

  • CONCAT(문자열1, 문자열2) / 문자열1 || 문자열2 / 문자열1 + 문자열2: 문자열 연결
SELECT CONCAT('hello', ' world') FROM dual;
-- 결과: hello world

숫자 함수

반올림/올림/내림 함수

  • ROUND(숫자, [소수자릿수]): 반올림
  • TRUNC(숫자, [소수자릿수]) / TRUNCATE(숫자, [소수자릿수]): 절삭
  • CEIL(숫자) / CEILING(숫자): 올림
  • FLOOR(숫자): 내림
SELECT ROUND(123.456, 2), TRUNC(123.456, 1), CEIL(123.1), FLOOR(123.9) FROM dual;
-- 결과: 123.46, 123.4, 124, 123

수학 연산 함수

  • MOD(숫자1, 숫자2) / 숫자1 % 숫자2: 나머지
  • ABS(숫자): 절대값
  • POWER(숫자, 제곱수): 제곱
  • SQRT(숫자): 제곱근
SELECT MOD(10, 3), ABS(-10), POWER(2, 3), SQRT(16) FROM dual;
-- 결과: 1, 10, 8, 4

날짜 함수

현재 날짜/시간 함수

  • SYSDATE / GETDATE(): 현재 날짜와 시간
SELECT SYSDATE FROM dual; -- 결과: 현재 날짜와 시간

날짜 연산 함수

  • ADD_MONTHS(날짜, 개월수) / DATEADD(month, 개월수, 날짜): 개월 수 더하기
  • MONTHS_BETWEEN(날짜1, 날짜2) / DATEDIFF(month, 날짜2, 날짜1): 두 날짜 사이의 개월 수
  • LAST_DAY(날짜): 해당 월의 마지막 날짜
SELECT ADD_MONTHS(SYSDATE, 3), LAST_DAY(SYSDATE) FROM dual;
-- 결과: 현재로부터 3개월 후, 현재 월의 마지막 날짜

날짜 추출 함수

  • EXTRACT(YEAR|MONTH|DAY FROM 날짜) / DATEPART(year|month|day, 날짜): 날짜에서 년/월/일 추출
SELECT EXTRACT(YEAR FROM SYSDATE), EXTRACT(MONTH FROM SYSDATE) FROM dual;
-- 결과: 현재 연도, 현재 월

변환 함수

  • TO_CHAR(날짜|숫자, 포맷) / CONVERT(varchar, 날짜|숫자, 포맷): 날짜나 숫자를 문자열로 변환
  • TO_NUMBER(문자열, [포맷]) / CONVERT(numeric, 문자열): 문자열을 숫자로 변환
  • TO_DATE(문자열, 포맷) / CONVERT(datetime, 문자열, 포맷): 문자열을 날짜로 변환
SELECT TO_CHAR(SYSDATE, 'YYYY-MM-DD'), TO_CHAR(12345.67, '$999,999.99') FROM dual;
-- 결과: 2025-05-13, $12,345.67

SELECT TO_NUMBER('12,345.67', '99,999.99'), TO_DATE('2022-01-01', 'YYYY-MM-DD') FROM dual;
-- 결과: 12345.67, 2022년 1월 1일

NULL 처리 함수

  • NVL(값1, 값2) / ISNULL(값1, 값2): 값1이 NULL이면 값2 반환, 아니면 값1 반환
  • NVL2(값, NULL아닐때값, NULL일때값): 값이 NULL이 아니면 두번째 인수, NULL이면 세번째 인수 반환
  • NULLIF(값1, 값2): 두 값이 같으면 NULL, 다르면 값1 반환
  • COALESCE(값1, 값2, ...): NULL이 아닌 첫 번째 값 반환
-- 커미션이 NULL이면 0으로 대체
SELECT ename, NVL(comm, 0) FROM emp;

-- 커미션이 있으면 O, 없으면 X
SELECT ename, NVL2(comm, 'O', 'X') 커미션유무 FROM emp;

-- NULL이 아닌 첫 번째 값 반환
SELECT COALESCE(NULL, NULL, 'Hello', 'World') FROM dual; -- 결과: Hello

조건부 함수

  • DECODE(컬럼/표현식, 조건1, 결과1, 조건2, 결과2, ..., 기본값): 조건에 따른 결과 반환(ORACLE)
  • CASE WHEN 조건1 THEN 결과1 [WHEN 조건2 THEN 결과2 ...] [ELSE 기본값] END: 조건에 따른 결과 반환
-- 부서번호에 따라 부서명 출력
SELECT ename, DECODE(deptno, 10, 'Accounting', 20, 'Research', 'Other') FROM emp;

-- 급여에 따라 등급 출력
SELECT ename, 
       CASE
           WHEN sal >= 3000 THEN 'High'
           WHEN sal >= 2000 THEN 'Medium'
           ELSE 'Low'
       END 급여등급
FROM emp;

그룹 함수

그룹 함수는 여러 행을 입력으로 받아 하나의 결과를 반환한다. NULL 값은 연산에서 제외된다.

기본 집계 함수

  • COUNT(컬럼|*): 행의 수 반환 (NULL 제외, COUNT(*) 제외)
  • SUM(컬럼): 합계
  • AVG(컬럼): 평균
  • MAX(컬럼): 최대값
  • MIN(컬럼): 최소값
SELECT 
    COUNT(*) 직원수, 
    SUM(sal) 급여합계,
    AVG(sal) 평균급여,
    MAX(sal) 최대급여,
    MIN(sal) 최소급여
FROM emp;

통계 함수

  • STDDEV(컬럼) / STDEV(컬럼): 표준편차
  • VARIANCE(컬럼) / VAR(컬럼): 분산
SELECT STDDEV(sal), VARIANCE(sal) FROM emp;

6. ORACLE과 SQL Server 문법 차이

기능ORACLESQL Server
현재 날짜 조회SYSDATEGETDATE()
FROM 절 생략불가능 (DUAL 사용)가능
문자열 연결CONCAT(str1, str2) 또는
str1 || str2
CONCAT(str1, str2) 또는
str1 + str2
날짜 더하기ADD_MONTHS(date, n)DATEADD(month, n, date)
날짜 간격MONTHS_BETWEEN(date1, date2)DATEDIFF(month, date2, date1)
NULL 위치 정렬ORDER BY col NULLS FIRST\|LAST
(기본: NULLS LAST)
옵션 없음
(기본: NULLS FIRST)
문자열 길이LENGTH(str)LEN(str)
부분 문자열 추출SUBSTR(str, pos, len)SUBSTRING(str, pos, len)
문자열 위치 찾기INSTR(str, substr, [pos, [occur]])CHARINDEX(substr, str, [pos])
조건부 결과DECODE(expr, search1, result1, ...)CASE 문 사용
NULL 치환NVL(expr, replace_value)ISNULL(expr, replace_value)
숫자 절삭TRUNC(num, [digits])FLOOR(num) (소수점 없이)
ROUND(num, digits, 1) (자릿수 지정)
특수 JOIN 구문FROM tab1, tab2 WHERE tab1.col(+) = tab2.col
(LEFT OUTER JOIN)
지원 안함 (ANSI 구문 사용)
페이징 처리ROWNUM 사용 또는
FETCH FIRST n ROWS ONLY (12c 이상)
TOP n 구문
변환 함수TO_CHAR, TO_DATE, TO_NUMBERCONVERT
표준편차STDDEVSTDEV
분산VARIANCEVAR
테이블 별칭FROM table alias (AS 생략)FROM table AS alias (AS 선택)

중요 문법 차이 예시

날짜 함수:

-- ORACLE
SELECT SYSDATE, ADD_MONTHS(SYSDATE, 3), MONTHS_BETWEEN('01-JAN-2022', '01-OCT-2021') FROM dual;

-- SQL Server
SELECT GETDATE(), DATEADD(month, 3, GETDATE()), DATEDIFF(month, '2021-10-01', '2022-01-01');

변환 함수:

-- ORACLE
SELECT TO_CHAR(SYSDATE, 'YYYY-MM-DD'), TO_DATE('2022-01-01', 'YYYY-MM-DD') FROM dual;

-- SQL Server
SELECT CONVERT(varchar, GETDATE(), 120), CONVERT(datetime, '2022-01-01', 120);

NULL 처리:

-- ORACLE
SELECT NVL(comm, 0), NVL2(comm, 'O', 'X') FROM emp;

-- SQL Server
SELECT ISNULL(comm, 0), CASE WHEN comm IS NOT NULL THEN 'O' ELSE 'X' END FROM emp;

OUTER JOIN:

-- ORACLE (오래된 문법)
SELECT e.ename, d.dname
FROM emp e, dept d
WHERE e.deptno(+) = d.deptno;  -- RIGHT OUTER JOIN

-- SQL Server (ANSI 표준 문법)
SELECT e.ename, d.dname
FROM dept d LEFT OUTER JOIN emp e ON d.deptno = e.deptno;

TOP N 쿼리:

-- ORACLE
SELECT * FROM (
    SELECT * FROM emp ORDER BY sal DESC
) WHERE ROWNUM <= 5;

-- ORACLE 12c 이상
SELECT * FROM emp
ORDER BY sal DESC
FETCH FIRST 5 ROWS ONLY;

-- SQL Server
SELECT TOP 5 * FROM emp
ORDER BY sal DESC;
profile
Tireless And Restless Debugging In Source : TARDIS

0개의 댓글