본문 바로가기

SQL/기본 개념

함수

▶ 함수(Function)

  • 함수란?
    - 컬럼의 값을 읽어서 연산한 결과를 반환하는 것
  • 단일행(Sigle Row) 함수
    - N개의 값을 읽어서 N개의 결과를 반환
  • 그룹(Group) 함수
    - N개의 값을 읽어서 1개의 결과를 반환
  • 함수는 SELECT절, WHERE절, ORDER BY절, GROUP BY절, HAVING절에서 사용 가능

▶ 단일행 함수(Function)

  • 문자열 관련 함수
    - LENGTH (문자열 | 컬럼명) : 문자열의 길이 반환
SELECT 'HELLO WORLD', LENGTH('HELLO WORLD') FROM DUAL;

    - INSTR (문자열 | 컬럼명, '찾을 문자열', [, 찾을 시작 위치 [, 순번])
      : 지정한 위치부터 지정한 순번째로 검색되는 문자의 시작 위치를 반환

EX-1) 문자열에서 맨 앞에 있는 'B'의 위치를 조회
SELECT 'AABAACAABBAA', INSTR('AABAACAABBAA', 'B') FROM DUAL; -- 결과 : 3

EX-2) 문자열 검색을 5번째부터 시작해서 처음 나오는 'B'의 위치를 조회
SELECT 'AABAACAABBAA', INSTR('AABAACAABBAA', 'B', 5) FROM DUAL; -- 결과 : 9

EX-3) 문자열 검색을 5번째부터 시작해서 두 번째에 나오는 'B'의 위치를 조회
SELECT 'AABAACAABBAA', INSTR('AABAACAABBAA', 'B', 5, 2) FROM DUAL; -- 결과 : 10

   - SUBSTR (문자열 | 컬럼명, 시작위치 [, 길이])
   : 문자열을 시작위치부터 지정된 길이만큼 잘라내서 반환 / 길이 미작성 시 시작위치 ~ 끝까지 잘라내서 반환

-- EX) EMPLOYEE 테이블에서 사원명, 이메일 아이디(@ 앞에까지의 문자열)을
-- 이메일 아이디 오름차순으로 조회
SELECT EMP_NAME, EMAIL, SUBSTR(EMAIL, 1, INSTR(EMAIL,'@')-1) "이메일 아이디" FROM EMPLOYEE
ORDER BY "이메일 아이디";

   - TRIM ( [ 옵션 ] '문자열' | 컬럼명 [ FROM '문자열' | 컬럼명 ] )
   : 옵션 ] LEADING(앞쪽), TRAILING(뒤쪽), BOTH(양쪽)
   : 주어진 컬럼이나 문자열의 앞, 뒤, 양쪽에 있는 지정된 문자를 제거

SELECT '     K    H     ', TRIM('     K    H     ') FROM DUAL; -- 양쪽 공백 제거(중간 미포함)

SELECT '---KH---', TRIM('-' FROM '---KH---') FROM DUAL; -- 결과 : KH

SELECT '---KH---', TRIM(LEADING '-' FROM '---KH---') FROM DUAL; -- 결과 : KH---

SELECT '---KH---', TRIM(TRAILING '-' FROM '---KH---') FROM DUAL; -- 결과 : ---KH

SELECT '---KH---', TRIM(BOTH '-' FROM '---KH---') FROM DUAL; -- 결과 : KH
  • 숫자 관련 함수

    - ABS (숫자 | 컬럼명) : 절대값

SELECT ABS(10), ABS(-10) FROM DUAL;

   - MOD (숫자 | 컬럼명, 숫자 | 컬럼명) :나머지 값 반환

EX) EMP 테이블에서 사원의 월급을 100만으로 나눴을 때, 나머지 조회

SELECT EMP_NAME, SALARY, MOD(SALARY, 1000000) FROM EMPLOYEE;

   - ROUND (숫자 | 컬럼명 [, 소수점 위치]) : 반올림

SELECT 123.456, ROUND(123.456) "소수점 첫째 자리에서 반올림" FROM DUAL; -- 결과 : 123

SELECT 123.456, ROUND(123.456, 1) "소수점 첫째 자리까지 출력" FROM DUAL; -- 결과 : 123.5

SELECT 123.456, ROUND(123.456, 2) "소수점 둘째 자리까지 출력" FROM DUAL; -- 결과 : 123.46


SELECT 123.456, ROUND(123.456, 0) "소수점 첫째 자리에서 반올림" FROM DUAL; -- 결과 : 123

SELECT 123.456, ROUND(123.456, -1) "소수점 0번째 자리에서 반올림" FROM DUAL; -- 결과 : 120

SELECT 123.456, ROUND(123.456, -2) "소수점 -1번째 자리에서 반올림" FROM DUAL; -- 결과 : 100

   - CEIL (숫자 | 컬럼명) : 올림
     FLOOR (숫자 | 컬럼명) : 내림
     → 전부 소수점 첫째 자리에서 올림 / 내림 처리

SELECT 123.5 CEIL(123.5), FLOOR(123.5) FROM DUAL;

   - TRUNC (숫자 | 컬럼명 [, 위치]) : 특정 위치 아래를 버림(절삭)

SELECT TRUNC(123.456, 1), TRUNC(123.456, -1) FROM DUAL;

   - 버림 / 내림 차이점

SELECT TRUNC(-123.5), FLOOR(-123.5) FROM DUAL;

  • 날짜(DATE) 관련 함수
    - SYSDAE : 시스템에 현재 시간(년, 월, 일, 시, 분, 초)을 반환

SELECT SYSDATE FROM DUAL;

   - SYSTIMESTAMP : SYSDATE + MS(1/1000초) 단위 추가

SELECT SYSTIMESTAMP FROM DUAL;

   - MONTHS_BETWEEN(날짜, 날짜) : 두 날짜의 개월 수 차이를 반환

SELECT ROUND(MONTHS_BETWEEN(SYSDATE, '2024/10/16')) || '개월' AS 수강기간 FROM DUAL;

   - ADD_MONTHS(날짜, 숫자) : 날짜에 숫자만큼의 개월 수를 더함

SELECT ADD_MONTHS(SYSDATE, 4) + 7 FROM DUAL; -- 현재일자 + 4개월 + 7일

   - LAST_DAY(날짜) : 해당 월의 마지막 날짜를 구함

SELECT LAST_DAY('25/04/01') FROM DAUL;

SELECT LAST_DAY(SYSDATE) FROM DUAL;

   - EXTRACT : 년, 월, 일 정보를 추출하여 리턴
     EXTRACT(YEAR FROM 날짜) : 연도만 추출
     EXTRACT(MONTH FROM 날짜) : 월(月)만 추출
     EXTRACT(DAY FROM 날짜) : 일(日)만 추출

EX-5) EMP 테이블에서 입사 월이 9월인 사원의 이름, 입사 년도, 입사 월, 입사 일을 조회

SELECT EMP_NAME,
EXTRACT(YEAR FROM HIRE_DATE)||'년' "입사 년도",
EXTRACT(MONTH FROM HIRE_DATE)||'월' "입사 월",
EXTRACT(DAY FROM HIRE_DATE)||'일' "입사 일"
FROM EMPLOYEE
WHERE EXTRACT(MONTH FROM HIRE_DATE) = 9;
  • 형변환 함수
    - 문자열(CHAR), 숫자(NUMBER), 날짜(DATE)끼리 형변환 가능

    ▷ 문자열로 변환
    - TO_CHAR( 날짜, [포맷] ) : 날짜형 데이터를 문자형 데이터로 변경
    - TO_CHAR( 숫자, [포맷] ) : 숫자형 데이터를 문자형 데이터로 변경

    - <패턴>
    - 9 : 숫자 한 칸을 의미 / 여러 개 작성 시 오른쪽 정렬
    - 0 : 숫자 한 칸을 의미 / 여러 개 작성 시 오른쪽 정렬 + 빈칸 0 추가
    - L : 현재 DB에 설정된 나라의 화폐 기호
SELECT TO_CHAR(1234,'99999') FROM DUAL;
-- 숫자 5칸, 오른쪽 정렬

SELECT TO_CHAR(1234,'00000') FROM DUAL;
-- 숫자 5칸, 오른쪽 정렬, 빈칸 0 추가

SELECT TO_CHAR(1000000, '9,999,999') FROM DUAL; -- 자릿수 구분

SELECT TO_CHAR(1000000, 'L9,999,999') FROM DUAL; -- 화폐기호(원화)

SELECT TO_CHAR(1000000, '$9,999,999') FROM DUAL; -- 화폐기호(달러)

   - 날짜에 TO_CHAR 적용
   ▷ YYYY : 년도 / YY : 년도 (짧게)
   ▷ RRRR : 년도 / RR : 년도 (짧게)
   ▷ MM : 월 / DD : 일
   ▷ AM 또는 PM : 오전 / 오후 표시
   ▷ HH : 시간 / HH24 : 24시간 표기법
   ▷ MI : 분 / SS : 초
   ▷ DAY : 요일(전체) / DY : 요일(요일 명만 표시)

SELECT SYSDATE, TO_CHAR(SYSDATE, 'DY DAY AM HH24:MI:SS') FROM DUAL;

EX-7) 직원들의 입사일을 '0000년 00월 00일 (요일명)' 형식으로 조회
SELECT EMP_NAME, TO_CHAR(HIRE_DATE, 'YYYY"년"MM"월"DD"일" (DY)') AS "입사일" FROM EMPLOYEE;

-- 년, 월, 일은 오라클에 등록된 날짜 표기 패턴이 아니라서 오류 발생 가능
--> 기존에 없던 패턴 추가할 경우 " "(쌍따옴표)로 감싸줘서 문자열 그대로 출력하게 함

   ▷ 날짜로 변환 TO_DATE
   - TO_DATE( 문자형 데이터, [포맷] ) : 문자형 데이터를 날짜로 변경
   - TO_DATE( 숫자형 데이터, [포맷] ) : 숫자형 데이터를 날짜로 변경
   → 지정된 포맷으로 날짜를 인식함

SELECT '2024-12-08', TO_DATE('2024-12-08') FROM DUAL;

SELECT TO_DATE('20241208') FROM DUAL;

SELECT TO_DATE(20241208) FROM DUAL;

SELECT TO_DATE('20241208 114500', 'YYMMDD HH24MISS') FROM DUAL;

-- 2024/12/08 11시 47분

SELECT TO_CHAR(TO_DATE('20241208 114700', 'YYMMDD HH24MISS'), 'YYYY/MM/DD HH24"시" MI"분"') FROM DUAL;

   - Y : 현재 세기(21세기 == 20XX == 2000년대)
   - R : 1세기 기준으로 절반(50년) 이상이면 이전 세기(1900년대) / 절반(50년) 미만이면 현재 세기(2000년대)

-- EX) EMP 테이블에서 각 직원이 태어난 생년월일 조회(단, 생년이 1950년대 미만인 직원은 없음)
SELECT EMP_NAME,
TO_DATE(SUBSTR(EMP_NO, 1, 6), 'RRMMDD') AS 생년월일 FROM EMPLOYEE;
SELECT TO_DATE('491119', 'RRMMDD') FROM DUAL; -- 결과 : 2049-11-19 00:00:00.000

SELECT TO_DATE('501119', 'RRMMDD') FROM DUAL; -- 결과 : 1950-11-19 00:00:00.000

   ▷ 숫자 형변환
   - TO_NUMBER( 문자데이터, [포맷] ) : 문자형 데이터를 숫자 데이터로 변경

SELECT '1,000,000' + 10 FROM DUAL; -- 계산 불가(오류 발생)

SELECT TO_NUMBER('1,000,000', '9,999,999') + 10 FROM DUAL; -- 결과 : 1,000,010

   ▷ NULL 처리 함수
   - NVL( 컬럼명, 컬럼값이 NULL일 때 바꿀 값) : NULL인 컬럼 값을 다른 값으로 변경

-- EX) EMP 테이블에서 이름, 급여, 보너스, 급여 * 보너스 조회
-- 보너스가 NULL인 경우, 급여 * 보너스 연산 결과도 NULL로 조회
-- 이를 방지하기 위해 NVL 함수 사용

SELECT EMP_NAME, SALARY, NVL(BONUS, 0), NVL(SALARY * BONUS, 0) FROM EMPLOYEE;

   - NVL2( 컬럼명, 바꿀 값 1, 바꿀 값2)
   : 해당 컬럼의 값이 있으면 바꿀 값1로 변경
   : 해당 컬럼의 값이 NULL이라면 바꿀 값2로 변경

-- EX) EMP 테이블에서
-- 기존 보너스를 받던 사원의 보너스를 0.7로
-- 보너스를 받지 못했던 사원의 보너스를 0.4로 변경하여
-- 이름, 기존 보너스, 변경된 보너스를 조회
-- (단, 기존 보너스는 값이 없을 경우 0으로 나타나게 함)

SELECT EMP_NAME 이름, 
NVL(BONUS, 0) "기존 보너스", 
NVL2(BONUS, 0.7, 0.4) "변경된 보너스"
FROM EMPLOYEE;

   ▷ 선택 함수
   - 여러 가지 경우에 따라 알맞은 결과를 선택할 수 있음

   - DECODE( 계산식 | 컬럼명, 조건값1, 선택값1, 조건값2, 선택값2, ..., 아무 것도 일치하지 않을 때)
   : 비교하고자 하는 값 또는 컬럼이 조건값과 같으면 선택값(결과값) 반환
   : 일치하는 값을 확인 (자바의 SWITCH 문과 비슷함)

-- EX) 직원들의 성별 구분해서 조회(DECODE)
SELECT EMP_NAME, DECODE( SUBSTR(EMP_NO,8,1), '1', '남자', '2', '여자')) 성별 FROM EMPLOYEE;

   - CASE WHEN 조건식 THEN 결과값
                WHEN 조건식 THEN 결과값
                ELSE 결과값
     END
   - 비교하고자 하는 값 또는 컬럼이 조건식과 같으면 결과값 반환
   - 조건은 범위값 가능

-- EX) 직원들의 성별 구분해서 조회(CASE - WHEN)
SELECT EMP_NAME,
   CASE WHEN SUBSTR(EMP_NO, 8, 1) = 1 THEN '남자'
        WHEN SUBSTR(EMP_NO, 8, 1) = 2 THEN '여자'
   END 성별
FROM EMPLOYEE;

   ▷ 그룹 함수
   - 하나 이상의 행을 그룹으로 묶어서 연산하여 총합, 평균 등의 하나의 결과 행으로 변환하는 함수
   - SUM( 숫자가 기록된 컬럼명) : 합계

-- EX) EMP 테이블에서 모든 직원의 급여 합계 조회
SELECT SUM(SALARY) "전 직원 급여 합" FROM EMPLOYEE;

   - AVG( 숫자가 기록된 컬럼명) : 평균

-- EX) 전 직원의 급여 평균 조회
SELECT AVG(SALARY) "전 직원 급여 평균" FROM EMPLOYEE;

   - MIN( 컬럼명 ) : 최소값
   - MAX( 컬럼명 ) : 최대값
   → 타입 제한 없음(숫자 : 대 / 소, 날짜: 과거 / 미래, 문자열: 문자 순서)

-- EX) 전 직원의 정보에서 가장 낮은 급여, 가장 빠른 입사일, 알파벳 순서가 가장 빠른 이메일 주소 조회
SELECT MIN(SALARY), MIN(HIRE_DATE), MIN(EMAIL) FROM EMPLOYEE;

   - 그룹 함수는 여러 항목을 동시에 작성 가능
   - 이때, 결과는 각 그룹 함수별 독립된 결과 조회

-- EX) 전 직원 정보 중에서 가장 높은 급여, 가장 늦은 입사일, 알파벳 순서가 가장 나중인 이메일 주소 조회
SELECT MAX(SALARY), MAX(HIRE_DATE), MAX(EMAIL) FROM EMPLOYEE;

   - ★ COUNT( * | 컬럼명) : 행의 개수를 헤아려서 반환 ★
   - COUNT( [DISTINCT] 컬럼명 ) : 중복을 제거한 행의 개수를 헤아려서 반환
   - COUNT( * ) : NULL을 포함한 전체 행의 개수를 반환
   - COUNT(컬럼명) : NULL을 제외한 실제 값이 기록된 행의 개수를 반환

-- EX) EMP 테이블 전체 행의 개수 조회 ( == 전체 직원 수)
SELECT COUNT(*) FROM EMPLOYEE; -- 결과 : 23
-- EX) 부서코드가 NULL이 아닌 행의 개수( == 직원 수)
SELECT COUNT(*) FROM EMPLOYEE
WHERE DEPT_CODE IS NOT NULL; -- 결과 : 21

   - COUNT(컬럼명) : NULL을 제외한 실제 값이 기록된 행의 개수를 반환

-- EX) 부서코드가 NULL이 아닌 행의 개수( == 직원 수)
SELECT COUNT(DEPT_CODE) FROM EMPLOYEE -- 결과 : 21 (위와 동일)
-- EX) EMP 테이블에서 남자 직원의 수 조회
-- 1) COUNT 함수
SELECT COUNT(*) 남직원 FROM EMPLOYEE
WHERE SUBSTR(EMP_NO, 8, 1) = 1;

-- 2) COUNT 함수 + CASE-WHEN 함수
SELECT COUNT(
   CASE WHEN SUBSTR(EMP_NO, 8, 1) = 1 THEN '남자'
   END 남직원)
FROM EMPLOYEE;

-- 3) SUM 함수 + DECODE 함수
SELECT SUM( DECODE( SUBSTR(EMP_NO, 8, 1), 1, 1 ) ) 남직원 FROM EMPLOYEE;
-- EX) EMP 테이블에 있는 부서의 개수 조회(중복 제외)
SELECT COUNT(DISTINCT DEPT_CODE) FROM EMPLOYEE;
--> 7행의 결과가 있지만, 1행이 NULL이기 때문에 COUNT 시 제외되어 6행 조회됨

'SQL > 기본 개념' 카테고리의 다른 글

JOIN  (0) 2024.12.16
GROUP BY / HAVING  (0) 2024.12.16
그룹(GROUP) 함수  (0) 2024.12.16
SELECT (DML / DQL)  (2) 2024.12.16
Database 개요  (0) 2024.12.16