관계형 데이터베이스, SELECT, 함수, WHERE, GROUP BY, ORDER BY절, 조인 등을 알아보자!
넓은 의미의 데이터베이스
: 일상적인 정보를 모아 놓은 것 자체
일반적 데이터베이스
: 필요에 따라 데이터
를 일정한 형태로 저장해 놓은 것
DBMS(Database Management System)
: 데이터 손상을 피하고, 필요한 데이터를 복구해주는 소프트웨어 등 데이터 관리에 관한 시스템
파일 시스템
관계형 데이터베이스
정규화
를 통한 이상현상 제거, 데이터 중복 피함동시성 관리
와 병행 제어
를 통해 많은 사용자가 데이터를 동시에 공유 및 조작 가능하게 함데이터 표준화
를 통한 데이터 품질 확보제약조건
으로 위배 데이터 입력 방지, 관계 연결 데이터 삭제 방지 등 데이터 무결성
보장장애
로부터 사용자가 입력,수정,삭제한 데이터가 반영될 수 있도록 보장시스템 다운, 재해
상황에서 데이터 복구
가능SQL(Structured Query Language)
: 관계형 데이터베이스에서 데이터 정의
, 데이터 조작
, 데이터 제어
를 위해 사용하는 언어
=> 데이터
를 집합
으로 취급
(ex. 포지션이 미드필더인 선수 정보 검색시 선수라는 집합
에서 조건을 만족하는 요구 집합
을 추출)
UNION 연산
은 UNION
기능으로INTERSECTION 연산
은 INTERSECT
기능으로DIFFERENCE 연산
은 EXCEPT(MINUS)
기능으로PRODUCT 연산
은 CROSS JOIN
기능으로 구현UNION
: 합집합을 제공하고, 공통 교집합의 중복 제거
UNION ALL
: 공통집합을 중복해 보여줌
INTERSECTION
: 두 집합의 공통집합
DIFFERENCE
: 첫 번째 집합에서 두 번째 집합과의 공통집합을 제외
PRODUCT
: JOIN 조건이 없는 경우 생길 수 있는 모든 데이터의 조합, CARTESIAN PRODUCT
SELECT 연산
은 WHERE
절로PROJECT 연산
은 SELECT
절로(NATURAL) JOIN 연산
은 다양한 JOIN
기능으로DIVIDE 연산
은 현재 사용 XSELECT
: SQL 문장에서는 WHERE 절의 조건절 기능으로 구현
PROJECT
: SQL 문장에서는 SELECT 절의 컬럼 선택 기능으로 구현
JOIN
: WHERE절의 INNER JOIN 조건과 함께 NATURAL JOIN, INNER JOIN, OUTER JOIN, USING 조건절, ON 조건절 등으로 발전
DIVIDE
: 왼쪽 집합을 'XZ'로 나누었을 때, 즉 'XZ'를 모두 갖고 있는 a가 답이 되는 기능, 현재 사용 X
정규화 과정
은 데이터 정합성
과 데이터 저장 공간 절약
을 위해 엔터티 분리
누가 키가 제일 큰지, 누가 몸무게가 제일 많이 나가는지 판단하기 위해 엑셀처럼 키는 키대로, 몸무게는 몸무게대로 순서를 정해 비교하는 것이 바람직하다.
데이터
는 관계형 데이터베이스
의 기본 단위인 테이블(TABLE)
형태로 저장
모든 자료는 테이블
에 등록되고, 테이블로부터 원하는 자료를 꺼내 옴
테이블
은 반드시 하나 이상의 칼럼
을 가져야 함
테이블
: 데이터를 저장하는 객체
, 관계형 데이터베이스의 기본 단위
=> 관계형 데이터베이스에서는 모든 데이터
를 칼럼
과 행
이라는 2차원 구조로 나타냄
칼럼
: 세로 방향
행
: 가로 방향
필드
: 칼럼
과 행
이 겹치는
하나의 공간
정규화
를 통해 데이터의 불필요한 중복
을 제거하여, 선수 테이블
과 팀 테이블
로 나누어 저장
=> 정규화
로 데이터의 정합성
확보와 입력,수정,삭제 시 이상현상
방지
ERD
: 테이블 간 서로의 상관관계
를 그림으로 도식화한 것
=> 엔터티
, 관계
, 속성
으로 구성
데이터 유형
: 데이터베이스의 테이블에 특정 자료를 입력할 때, 그 자료를 받아들일 공간을 자료의 유형
별로 나누는 기준
지정한 크기
: 선언 당시에 지정한 데이터의 크기를 넘어선 자료가 입력시 에러 발생
varchar
가변 길이
실제 데이터 크기
char
보다 작은 영역
에 저장 가능공백
도 하나의 문자
로 취급하므로 끝의 공백
이 다르면 다른 문자
로 판단char
문자열 비교
시 공백
을 채워서 비교끝의 공백
만 다른 문자열
은 같다
고 판단예) CHAR 유형'AA' = 'AA '
예) VARCHAR 유형 'AA' ≠ 'AA '
select
: 사용자가 입력한 데이터를 조회
select [all/distinct] 출력 대상 칼럼명, 출력 대상 칼럼명, ...
from 출력 대상 컬럼이 있는 테이블명;
all
: Default 옵션
, 중복된 데이터가 있어도 모두 출력distinct
: 중복된 데이터가 있을 경우 1건
으로 처리
SELECT PLAYER_ID, PLAYER_NAME, TEAM_ID, POSITION, HEIGHT, WEIGHT, BACK_NO
FROM PLAYER;
select all position
from player;
-- all은 생략 가능한 키워드이므로 위와 같은 결과 출력
select position
from player;
select distinct position
from player;
null
까지 총 5건의 데이터만 출력됨
애스터리스크(*)
: 해당 테이블의 모든 칼럼
의 정보를 보고 싶을 경우 사용
select *
from 테이블명;
select *
from emp;
칼럼 레이블(LABLE)
은 기본적으로 대문자
로 보인다.
레이블의 정렬
좌측 정렬
: 문자
및 날짜
데이터우측 정렬
: 숫자
데이터칼럼 별명(ALIAS)
as
키워드를 사용 가능 (옵션)이중 인용부호(")
는 alias가 공백
, 특수문자
를 포함할 경우, 대소문자 구분
이 필요할 경우 사용SELECT PLAYER_NAME AS 선수명, POSITION AS 위치, HEIGHT AS 키, WEIGHT AS 몸무게
FROM PLAYER;
--as는 생략 가능하므로 위와 같음
SELECT PLAYER_NAME 선수명, POSITION 위치, HEIGHT 키, WEIGHT 몸무게
FROM PLAYER;
SELECT PLAYER_NAME "선수 이름", POSITION "그라운드 포지션", HEIGHT "키", WEIGHT "몸무게"
FROM PLAYER;
number
과 date
자료형에 대해 적용
우선순위
: (), *, /, +, -
순
SELECT PLAYER_NAME 이름, HEIGHT - WEIGHT "키-몸무게"
FROM PLAYER;
합성(CONCATENATION) 연산자
: 문자
와 문자
를 연결
2개의 수직 바(||)
사용 (oracle)+
사용 (SQL Server)CONCAT (string1, string2) 함수
사용 (oracle, SQL Server)칼럼
과 문자
또는 다른 칼럼
과 연결새로운 칼럼
생성--Oracle
SELECT PLAYER_NAME || '선수,' || HEIGHT || 'cm,' || WEIGHT || 'kg' 체격정보
FROM PLAYER;
--SQL Server
SELECT PLAYER_NAME +'선수, '+ HEIGHT +'cm, '+ WEIGHT +'kg'체격정보
FROM PLAYER;
함수(Function)
은 벤더에서 제공하는 함수인 내장 함수(Built-in Function)
과 사용자가 정의할 수 있는 함수(User Defined Function)
으로 나뉨
내장 함수
: SQL을 더 강력하게 해주고, 데이터 값
을 간편하게 조작하는 데 사용
단일행 함수(Single-Row)
: 함수 입력 값
이 단일행 값
이 입력다중행 함수(Multi-Row)
: 여러 행
의 값이 입력집계함수(Aggregate)
, 그룹 함수(Group)
, 윈도우 함수(Window)
로 나뉨함수는 입력되는 값이 아무리 많아도 출력은 하나
단일행 함수
는 단일행 내에 있는 하나의 값
또는 여러 값
이 입력 인수
로 표현
다중행 함수
는 여러 레코드의 값
들을 입력 인수로 사용
단일행 함수
의 특징
개별적으로 작용
해 데이터 값들을 조작하고, 각각의 행에 대한 조작 결과 리턴상수, 변수, 표현식
이 사용 가능하고, 하나의 인수를 가질 수 있지만 여러 개의 인수를 가질 수도 있음함수의 중첩
가능문자형 함수
: 문자 데이터
를 매개 변수로 받아들여 문자
나 숫자 값
을 리턴
--oracle
SELECT LENGTH('SQL Expert') FROM DUAL;
--sql server
SELECT LEN('SQL Expert') AS ColumnLength;
oracle
은 select절
과 from절
두 개의 절을 select문장
의 필수 절
로 지정해 dual
테이블 필요
DUAL 테이블
select~from~
의 형식을 갖추기 위한 일종의 dummy 테이블desc dual;
select * from dual;
Sybase
나 SQL Server
는 select절
만으로도 sql문장 수행 가능
SELECT CONCAT(PLAYER_NAME, ' 축구선수') 선수명 FROM PLAYER;
--oracle
SELECT PLAYER_NAME || ' 축구선수' AS 선수명 FROM PLAYER;
--sql server
SQL Server SELECT PLAYER_NAME + ' 축구선수' AS 선수명 FROM PLAYER;
--oracle
SELECT STADIUM_ID, DDD|| ')' || TEL as TEL, LENGTH(DDD||'-'||TEL) as T_LEN FROM STADIUM;
--sql server
SELECT STADIUM_ID, DDD+')'+TEL a s TEL, LEN(DDD+'-'+TEL) as T_LEN FROM STADIUM;
숫자형 함수
: 숫자
데이터를 입력받아 처리 후 숫자
리턴
SELECT ENAME, ROUND(SAL/12,1), TRUNC(SAL/12,1) FROM EMP;
SELECT ENAME, ROUND(SAL/12), CEIL(SAL/12) FROM EMP;
날짜형 함수
: DATE
타입의 값을 연산
데이터베이스는 날짜를 저장할 때, 세기/연/월/일/시/분/초
와 같은 숫자
형식으로 변환해 저장
=> 숫자
로 저장하기 때문에 산술 연산자로 계산 가능
SYSDATE + 10/(24*60*60)
1/24
: 1일
을 24
로 나눔 (1시간
)1/24/60/6
: 10초
--oracle
SELECT SYSDATE FROM DUAL;
--sql server
SELECT GETDATE() AS CURRENTTIME;
--oracle
SELECT ENAME, HIREDATE,
EXTRACT(YEAR FROM HIREDATE) 입사년도,
EXTRACT(MONTH FROM HIREDATE) 입사월,
EXTRACT(DAY FROM HIREDATE) 입사일
FROM EMP;
SELECT ENAME, HIREDATE,
TO_NUMBER(TO_CHAR(HIREDATE,'YYYY')) 입사년도,
TO_NUMBER(TO_CHAR(HIREDATE,'MM')) 입사월,
TO_NUMBER(TO_CHAR(HIREDATE,'DD')) 입사일
FROM EMP;
--sql server
SELECT ENAME, HIREDATE,
DATEPART(YEAR, HIREDATE) 입사년도,
DATEPART(MONTH, HIREDATE) 입사월,
DATEPART(DAY, HIREDATE) 입사일
FROM EMP;
SELECT ENAME, HIREDATE,
YEAR(HIREDATE) 입사년도,
MONTH(HIREDATE) 입사월,
DAY(HIREDATE) 입사일
FROM EMP;
변환형 함수
: 특정 데이터 타입
을 다양한 형식으로 출력하고자 할 경우 사용
암시적 데이터 유형 변환
의 경우 성능 저하
가 발생할 수 있다.
--oracle
SELECT TO_CHAR(SYSDATE, 'YYYY/MM/DD') 날짜,
TO_CHAR(SYSDATE, 'YYYY. MON, DAY') 문자형
FROM DUAL;
--sql server
CONVERT(VARCHAR(10),GETDATE(),111) AS CURRENTDATE CURRNETDATE;
-- 2024-04-20 으로 출력됨
-- convert 함수의 111은 날짜 형식을 'yyyy/mm/dd'로 지정
SELECT TO_CHAR(123456789/1200,'$999,999,999.99') 환율반영달러,
TO_CHAR(123456789,'L999,999,999') 원화 --L은 로컬 화폐 단위
FROM DUAL;
--oracle
SELECT TEAM_ID, TO_NUMBER(ZIP_CODE1,'999') + TO_NUMBER(ZIP_CODE2,'999') 우편번호합
FROM TEAM;
--sql server
SELECT TEAM_ID, CAST(ZIP_CODE1 AS INT) + CAST(ZIP_CODE2 AS INT) 우편번호합
FROM TEAM;
CASE 표현
: IF-THEN-ELSE
와 유사 (= oracle의 DECODE 함수
)
--PL/SQL 로직
IF SAL > 2000
THEN REVISED_SALARY = SAL
ELSE REVISED_SALARY = 2000
END IF
--case 표현
SELECT ENAME,
CASE WHEN SAL > 2000 THEN SAL ELSE 2000 END REVISED_SALARY
FROM EMP;
Simple Case Expression
case 조건 열
when 조건 값 then 무엇1
...
end
--oracle decode와 기능 동일
SELECT LOC,
CASE LOC WHEN 'NEW YORK' THEN 'EAST'
WHEN 'BOSTON' THEN 'EAST'
WHEN 'CHICAGO' THEN 'CENTER'
WHEN 'DALLAS' THEN 'CENTER'
ELSE 'ETC'
END as AREA
FROM DEPT;
Searched Case Expression
case when 조건열=조건값 then 무엇
...
end
-- equi 조건 외에도 여러 조건을 이용한 조건절 사용 가능
SELECT ENAME,
CASE WHEN SAL >= 3000 THEN 'HIGH'
WHEN SAL >= 1000 THEN 'MID'
ELSE 'LOW'
END AS SALARY_GRADE
FROM EMP;
--중첩 가능
SELECT ENAME, SAL,
CASE WHEN SAL >= 2000 THEN 1000
ELSE (CASE WHEN SAL >= 1000 THEN 500 ELSE 0 END)
END as BONUS
FROM EMP;
결과값을 null이 아닌 다른 값을 얻고자 할 때 사용.
null값의 대상이 숫자
유형이면 주로 0
, 문자
유형이면 x
로 주로 바꿈
--oracle
NVL(NULL 판단 대상, 'NULL일 때 대체값')
--sql server
ISNULL(NULL 판단 대상, 'NULL일 때 대체값')
--oracle
SELECT NVL(NULL, 'NVL-OK') NVL_TEST FROM DUAL;
--sql server
SELECT ISNULL(NULL, 'NVL-OK') ISNULL_TEST ;
--oracle
SELECT NVL('Not-Null', 'NVL-OK') NVL_TEST FROM DUAL;
--sql server
SELECT ISNULL('Not-Null', 'NVL-OK') ISNULL_TEST;
--oracle
SELECT PLAYER_NAME 선수명, POSITION, NVL(POSITION,'없음') 포지션
FROM PLAYER
WHERE TEAM_ID = 'K08';
--sql server
SELECT PLAYER_NAME 선수명, POSITION, ISNULL(POSITION,'없음') 포지션
FROM PLAYER
WHERE TEAM_ID = 'K08';
--case로 표현 가능
SELECT PLAYER_NAME 선수명, POSITION,
CASE WHEN POSITION IS NULL THEN '없음' ELSE POSITION END AS 포지션
FROM PLAYER
WHERE TEAM_ID = 'K08';
--oracle
NVL2(NULL 판단 대상, 'NULL이 아닐 때 대체값','NULL일 때 대체값');
-- 인수1이 null이면 인수3 반환, 인수1이 null이 아니면 인수2 반환
-- 매니저가 NULL인 경우 빈칸이 아닌 9999로 출력하기 위해 NVL/ISNULL 사용
SELECT NVL(MGR,9999) MGR FROM EMP WHERE ENAME='KING';
공집합
: 조건에 맞는 데이터가 한 건도 없는
경우
select 1 from dual where 1=2;
공집합
은 NULL 데이터
와는 다르다
SELECT MGR FROM EMP WHERE ENAME='JSC';
인수의 값이 공집합
인 경우, nvl/isnull
함수를 사용해도 공집합
이 출력
SELECT NVL(MGR, 9999) MGR FROM EMP WHERE ENAME='JSC';
집계함수
와 스칼라 서브쿼리
는 인수의 결과 값이 공집합
이라도 NULL
출력
SELECT MAX(MGR) MGR FROM EMP WHERE ENAME='JSC';
집계함수
를 인수로 할 경우 nvl/isnull 함수 사용해서 9999로 출력 가능
SELECT NVL(MAX(MGR), 9999) MGR FROM EMP WHERE ENAME='JSC';
NULLIF(EXPR1, EXPR2)
NULLIF
: EXPR1이 EXPR2와 같으면
NULL
, 같지 않으면
EXPR1
을 리턴
SELECT ENAME, EMPNO, MGR, NULLIF(MGR,7698) NUIF FROM EMP;
--case표현 가능
SELECT ENAME, EMPNO, MGR,
CASE WHEN MGR = 7698 THEN NULL ELSE MGR
END NUIF
FROM EMP;
COALESCE( EXPR1, EXPR2, ...)
COALESCE
: 인수의 숫자 한정X, expr 중 null이 아닌 최초의 expr
을 리턴, 모두 null이면 null 리턴
SELECT ENAME, COMM, SAL, COALESCE(COMM, SAL) COAL FROM EMP;
--case 표현 가능
SELECT ENAME, COMM, SAL,
CASE WHEN COMM IS NOT NULL THEN COMM
ELSE (CASE WHEN SAL IS NOT NULL THEN SAL ELSE NULL END)
END COAL
FROM EMP;
where
: 두 개 이상의 테이블에 대한 조인 조건
을 기술하거나, 결과 제한
을 위한 조건 기술
select [distinct/all] 컬럼명 [alias 명]
from 테이블명
where 조건식;
where절 구성
where절
에 사용되는 연산자
괄호
로 묶은 연산이 제일 먼저 처리비교 연산자
, SQL 연산자
처리부정
연산자 처리논리
연산자 중 and, or
순서대로 처리비교 연산자
로 칼럼
들을 특정한 값
들과 조건을 비교하는 데 사용
SELECT PLAYER_NAME 선수이름, POSITION 포지션, BACK_NO 백넘버, HEIGHT 키
FROM PLAYER
WHERE TEAM_ID = 'K02' ;
숫자
유형의 칼럼의 경우, 숫자로 변환 가능한 문자열
과 비교시 상대 타입
을 숫자 타입으로 변경해 비교
where height>='170'
이라고 표현시, '170'
이 170
으로 변경되어 처리
SELECT PLAYER_NAME 선수이름, POSITION 포지션, BACK_NO 백넘버, HEIGHT 키
FROM PLAYER
WHERE TEAM_ID IN ('K02','K07');
다중 리스트
를 이용한 IN 연산자
는 성능 측면에서도 장점이 있어 적극 사용 권고
SELECT ENAME, JOB, DEPTNO
FROM EMP
WHERE (JOB, DEPTNO) IN (('MANAGER',20),('CLERK',30));
-- 아래와 다름
SELECT ENAME, JOB, DEPTNO
FROM EMP
WHERE JOB IN ('MANAGER','CLERK')
AND DEPTNO IN (20,30);
와일드카드(WildCard)
: 한 개
혹은 0개 이상
의 문자를 대신해 사용하기 위한 특수문자
SELECT PLAYER_NAME 선수이름, POSITION 포지션, BACK_NO 백넘버, HEIGHT 키
FROM PLAYER
WHERE PLAYER_NAME LIKE '장%';
BETWEEN a AND b
: 범위에서 a
와 b
의 값을 포함
SELECT PLAYER_NAME 선수이름, POSITION 포지션, BACK_NO 백넘버, HEIGHT 키
FROM PLAYER
WHERE HEIGHT BETWEEN 170 AND 180;
null
값과의 비교 연산
은 거짓(FALSE)
를 리턴
SELECT PLAYER_NAME 선수이름, POSITION 포지션, BACK_NO 백넘버, HEIGHT 키
FROM PLAYER
WHERE POSITION = NULL;
-- where 조건절이 false가 되어 만족하는 레코드가 하나도 안나오는 공집합
SELECT PLAYER_NAME 선수이름, POSITION 포지션, TEAM_ID
FROM PLAYER
WHERE POSITION IS NULL;
논리 연산자
: 비교 연산자나 SQL 연산자들로 이루어진 여러 개의 조건들을 논리적
으로 연결시키기 위해 사용
SELECT PLAYER_NAME 선수이름, POSITION 포지션, BACK_NO 백넘버, HEIGHT 키
FROM PLAYER
WHERE TEAM_ID IN ('K02','K07') AND POSITION = 'MF';
SELECT PLAYER_NAME 선수이름, POSITION 포지션, BACK_NO 백넘버, HEIGHT 키
FROM PLAYER
WHERE TEAM_ID = 'K02'
AND NOT POSITION = 'MF'
AND NOT HEIGHT BETWEEN 175 AND 185;
--위와 동일
SELECT PLAYER_NAME 선수이름, POSITION 포지션, BACK_NO 백넘버, HEIGHT 키
FROM PLAYER
WHERE TEAM_ID = 'K02'
AND POSITION <> 'MF'
AND HEIGHT NOT BETWEEN 175 AND 185;
SELECT PLAYER_NAME 선수이름, NATION 국적
FROM PLAYER
WHERE NATION IS NOT NULL;
집계함수(Aggregate Function)
여러 행
들의 그룹이 모여 그룹당
단 하나의 결과를 돌려주는 함수GROUP BY절
은 행
들을 소그룹화SELECT절
, HAVING절
, ORDER BY절
에 사용 가능집계함수명 ([distinct|all] 칼럼이나 표현식)
all
: default옵션으로, 생략 가능distinct
: 같은 값을 하나의 데이터로 간주시 사용SELECT COUNT(*) "전체 행수", COUNT(HEIGHT) "키 건수",
MAX(HEIGHT) 최대키, MIN(HEIGHT) 최소키, ROUND(AVG(HEIGHT),2) 평균키
FROM PLAYER;
count(*)
는 전체 행의 개수를 출력
count(height)
는 null값이 아닌
건수만 출력
group by
: 데이터들을 작은 그룹
으로 분류해 소그룹에 대한 항목별
통계 정보
얻을 때 사용
select [distinct] 칼럼명 [alias명]
from 테이블명
[where 조건식]
[group by 칼럼(Column)이나 표현식]
[having 그룹조건식];
group by 절
과 having 절
특성
group by절
을 통해 소그룹별 기준을 정한 후, select절에 집계함수
사용null값 제외
alias 명 사용 X
where절
에 올 수 없음where절
은 전체 데이터를 group으로 나누기 전 행 제거having절
은 group by절의 기준 항목이나 소그룹의 집계함수를 이용한 조건 표시 가능having
절에 제한 조건을 두어 조건 만족하는 내용만 출력having
절은 일반적으로 group by
절 뒤에 위치SELECT POSITION 포지션, AVG(HEIGHT) 평균키 FROM PLAYER;
group by
절에 그룹 단위
를 표시해주어야 select
절에서 그룹 단위 칼럼
과 집계함수
사용 가능
SELECT POSITION 포지션, COUNT(*) 인원수, COUNT(HEIGHT) 키대상,
MAX(HEIGHT) 최대키, MIN(HEIGHT) 최소키, ROUND(AVG(HEIGHT),2) 평균키
FROM PLAYER
GROUP BY POSITION;
포지션
과 키 정보가 없는
선수가 3명이라는 정보를 얻을 수 있다.
HAVING
: 그룹을 나타내는 결과 집합의 행에 조건 적용
SELECT POSITION 포지션, ROUND(AVG(HEIGHT),2) 평균키
FROM PLAYER
GROUP BY POSITION
HAVING AVG(HEIGHT) >= 180;
group by
절과 having
절 순서를 바꾸어도 에러가 없다 (sql server는 문법오류)
SELECT POSITION 포지션, ROUND(AVG(HEIGHT),2) 평균키
FROM PLAYER
GROUP BY POSITION
HAVING MAX(HEIGHT) >= 190;
having절
은 select절
에 사용되지 않은 컬럼
이나 집계함수
라도, group by
절의 기준 항목
이나 소그룹의 집계함수
를 이용한 조건 표시 가능
집계함수(case())~group by
: 반복되는 칼럼의 경우 구분 칼럼을 두어, 여러 개의 레코드로 만들어진 집합을 정해진 칼럼 수만큼 확장해 집계 보고서
를 만드는 유용한 기능
--개별 데이터 확인
--월별 데이터 추출
SELECT ENAME, DEPTNO, EXTRACT(MONTH FROM HIREDATE) 입사월, SAL FROM EMP;
-- 월별 데이터 구분
SELECT ENAME, DEPTNO,
CASE MONTH WHEN 1 THEN SAL END M01,
CASE MONTH WHEN 2 THEN SAL END M02,
CASE MONTH WHEN 3 THEN SAL END M03,
CASE MONTH WHEN 4 THEN SAL END M04,
CASE MONTH WHEN 5 THEN SAL END M05,
CASE MONTH WHEN 6 THEN SAL END M06,
CASE MONTH WHEN 7 THEN SAL END M07,
CASE MONTH WHEN 8 THEN SAL END M08,
CASE MONTH WHEN 9 THEN SAL END M09,
CASE MONTH WHEN 10 THEN SAL END M10,
CASE MONTH WHEN 11 THEN SAL END M11,
CASE MONTH WHEN 12 THEN SAL END M12
FROM (SELECT ENAME, DEPTNO, EXTRACT(MONTH FROM HIREDATE) MONTH, SAL
FROM EMP);
--부서별 데이터 집계
SELECT DEPTNO,
AVG(CASE MONTH WHEN 1 THEN SAL END) M01,
AVG(CASE MONTH WHEN 2 THEN SAL END) M02,
AVG(CASE MONTH WHEN 3 THEN SAL END) M03,
AVG(CASE MONTH WHEN 4 THEN SAL END) M04,
AVG(CASE MONTH WHEN 5 THEN SAL END) M05,
AVG(CASE MONTH WHEN 6 THEN SAL END) M06,
AVG(CASE MONTH WHEN 7 THEN SAL END) M07,
AVG(CASE MONTH WHEN 8 THEN SAL END) M08,
AVG(CASE MONTH WHEN 9 THEN SAL END) M09,
AVG(CASE MONTH WHEN 10 THEN SAL END) M10,
AVG(CASE MONTH WHEN 11 THEN SAL END) M11,
AVG(CASE MONTH WHEN 12 THEN SAL END) M12
FROM (SELECT ENAME, DEPTNO, EXTRACT(MONTH FROM HIREDATE) MONTH, SAL
FROM EMP)
GROUP BY DEPTNO ;
하나의 SQL 문장으로 리포트를 작성할 수 있어 처리 속도나 자원 활용 측면에서 효율적
다중행 함수
를 사용하는 경우, nvl함수
를 다중행 함수 안
에 사용할 필요 X(부하 발생)
다중행 함수
는 전체 건수
가 null값
인 경우만 함수 결과가 null
이 나오고, 일부만 null
인 경우 null인 행
을 다중 행 함수 대상에서 제외
case표현
에서 else
생략시, default값
이 null
decode
함수에서 4번째 인자 생략시 null
이 default
불필요하게 else절에 0
을 지정하면, sum연산에 0이 포함되므로 같은 결과를 얻는다면 가능한 else절
에 상수값
을 지정하지 않거나 생략하도록 함
SELECT TEAM_ID,
NVL(SUM(CASE POSITION WHEN 'FW' THEN 1 ELSE 0 END),0) FW,
NVL(SUM(CASE POSITION WHEN 'MF' THEN 1 ELSE 0 END),0) MF,
NVL(SUM(CASE POSITION WHEN 'DF' THEN 1 ELSE 0 END),0) DF,
NVL(SUM(CASE POSITION WHEN 'GK' THEN 1 ELSE 0 END),0) GK,
COUNT(*) SUM
FROM PLAYER
GROUP BY TEAM_ID;
sum(nvl(sal,0))
또는 sum(isnull(sal,0)
에서 급여가 null
인 경우 자연스럽게 sum연산
에서 빠지므로 불필요하게 nvl 함수를 사용하지 않아도 된다. nvl(sum(sal),0)
으로 사용하면 된다.
SELECT TEAM_ID,
NVL(SUM(CASE POSITION WHEN 'FW' THEN 1 END),0) FW,
NVL(SUM(CASE POSITION WHEN 'MF' THEN 1 END),0) MF,
NVL(SUM(CASE POSITION WHEN 'DF' THEN 1 END),0) DF,
NVL(SUM(CASE POSITION WHEN 'GK' THEN 1 END),0) GK,
COUNT(*) SUM
FROM PLAYER
GROUP BY TEAM_ID;
ORDER BY
: 특정 칼럼
을 기준으로 정렬
에 사용
=> 칼럼명
대신 alias명
이나 칼럼 순서
를 나타내는 정수
사용 가능
=> 기본적으로 오름차순
select 칼럼명 [alias명]
from 테이블명
[where 조건식]
[group by 칼럼이나 표현식]
[having 그룹조건식]
[order by 칼럼이나 표현식 [asc 또는 desc]];
order by절
의 정렬 방식
ASC(Ascending)
: 조회한 데이터를 오름차순
정렬 (기본값, 생략가능)DESC(Descending)
: 조회한 데이터를 내림차순
정렬SELECT PLAYER_NAME 선수명, POSITION 포지션, BACK_NO 백넘버
FROM PLAYER
ORDER BY 포지션 DESC;
NULL 정렬
NULL값
을 가장 큰 값
취급NULL값
을 가장 작은 값
취급order by절
의 특징
오름차순(asc)
숫자형
데이터 타입은 오름차순시 가장 작은 값
부터 출력날짜형
데이터 타입은 오름차순시 가장 빠른 값
부터 출력oracle
은 null값
을 가장 큰
값으로 간주해 오름차순
시 마지막
, 내림차순
시 가장 먼저
sql server
는 null값
을 가장 작은
값으로 간주해 오름차순
시 먼저
, 내림차순
시 가장 마지막
칼럼명, alias명, 칼럼 순서
를 같이 혼용 가능SELECT DNAME, LOC AREA, DEPTNO
FROM DEPT
ORDER BY 1, AREA, 3 DESC;
select 칼럼명 [alias명]--5
from 테이블명 --1
where 조건식 --2
group by 칼럼이나 표현식 --3
having 그룹조건식 --4
order by 칼럼이나 표현식;--6
order by
절에는 select 목록
에 나타나지 않은 문자형 항목
이 포함 가능
=> distinct
지정, group by
존재, union
연산자 존재 시 불가능
=> 관계형 DB가 데이터를 메모리에 올릴 때 행 단위
로 모든 칼럼
을 가져오므로 가능
--select절에 없는 mgr 컬럼으로 정렬 가능
SELECT EMPNO, ENAME FROM EMP ORDER BY MGR;
SELECT MGR
FROM (SELECT EMPNO, ENAME FROM EMP ORDER BY MGR);
서브쿼리
의 select절
에서 선택되지 않은 칼럼들은 범위를 벗어나면 더이상 사용 불가
group by
사용시, 그룹핑 기준
에 사용된 칼럼
과 집계함수
에 사용될 수 있는 숫자형 데이터 칼럼
으로 집합을 새로 만듦, 개별 데이터는 필요 없으므로 저장X
=> group by
이후 select절이나 order by절에서 개별 데이터 사용시 에러
SELECT JOB, SAL --select절에 일반 칼럼
FROM EMP
GROUP BY JOB
HAVING COUNT(*) > 0
ORDER BY SAL;
SELECT JOB
FROM EMP
GROUP BY JOB
HAVING COUNT(*) > 0
ORDER BY SAL; --order by 절에 일반 칼럼
-- order by 절에 집계 칼럼 사용
select job, sum(sal) as salary_sum
from emp
group by job
having sum(sal)>5000
order by sum(sal);
조인(JOIN)
: 두 개 이상의 테이블들을 연결
해 데이터를 출력
FROM
절에 여러 테이블이 나열되더라도 SQL
에서 데이터 처리시 단 두개의 집합 간
에만 조인
발생
=>ex. A,B,C,D 조인시 (((A join D) join C) join B)와 같이 순차적으로 조인
처리
EQUI JOIN
: 두 개의 테이블 간에 칼럼 값
들이 정확
하게 일치하는 경우 사용
SELECT 테이블1.칼럼명, 테이블2.칼럼명, ...
FROM 테이블1, 테이블2
WHERE 테이블1.칼럼명1 = 테이블2.칼럼명2; --where절에 join 조건 기술, "=" 사용
--ansi/iso 표준
SELECT 테이블1.칼럼명, 테이블2.칼럼명, ...
FROM 테이블1 INNER JOIN 테이블2
ON 테이블1.칼럼명1 = 테이블2.칼럼명2; --on 절에 join 조건 기술
SELECT PLAYER.PLAYER_NAME 선수명, TEAM.TEAM_NAME 소속팀명
FROM PLAYER, TEAM
WHERE PLAYER.TEAM_ID = TEAM.TEAM_ID;
inner join
에 참여하는 테이블이 n개
일 경우, 필요한 조인 조건은 n-1개
이상이 필요
SELECT PLAYER.PLAYER_NAME, PLAYER.BACK_NO, PLAYER.TEAM_ID, TEAM.TEAM_NAME, TEAM.REGION_NAME
FROM PLAYER, TEAM
WHERE PLAYER.TEAM_ID = TEAM.TEAM_ID;
where절
에 추가적인 제한 조건 입력 가능
SELECT P.PLAYER_NAME 선수명, P.BACK_NO 백넘버, T.REGION_NAME 연고지, T.TEAM_NAME 팀명
FROM PLAYER P, TEAM T
WHERE P.TEAM_ID = T.TEAM_ID AND P.POSITION = 'GK'
ORDER BY P.BACK_NO;
테이블
에 대한 alias
적용해 sql 작성시 where절
과 select절
에는 테이블명이 아닌 alias
를 사용해야 함
SELECT T.REGION_NAME, T.TEAM_NAME, T.STADIUM_ID, S.STADIUM_NAME, S.SEAT_COUNT
FROM TEAM T, STADIUM S
WHERE T.STADIUM_ID = S.STADIUM_ID;
Non EQUI JOIN
: 두 개 테이블 간 논리적인 연관 관계를 가지나, 칼럼 값
들이 서로 일치하지 않는
경우 사용
=> =
가 아닌 Between, >, >=, <, <=
등의 연산자들을 사용해 JOIN 수행
SELECT 테이블1.칼럼명, 테이블2.칼럼명, ...
FROM 테이블1, 테이블2
WHERE 테이블1.칼럼명1 BETWEEN 테이블2.칼럼명1 AND 테이블2.칼럼명2;
사원이 받고 있는 급여가 어느 등급
에 속하는지 알기 위해 급여등급
테이블을 생성하자
create table SALGRADE(
GRADE number,
LOSAL number,
HISAL number);
insert into salgrade values(1,700,1200);
insert into salgrade values(2,1201,1400);
insert into salgrade values(3,1401,2000);
insert into salgrade values(4,2001,3000);
insert into salgrade values(5,3001,9999);
SELECT E.ENAME 사원명, E.SAL 급여, S.GRADE 급여등급
FROM EMP E, SALGRADE S
WHERE E.SAL BETWEEN S.LOSAL AND S.HISAL;
선수 테이블과 운동장 테이블은 서로 관계가 없어 세 개의 테이블을 조인
해야만 원하는 데이터를 얻을 수 있음
SELECT P.PLAYER_NAME 선수명, P.POSITION 포지션, T.REGION_NAME 연고지, T.TEAM_NAME 팀명, S.STADIUM_NAME 구장명
FROM PLAYER P, TEAM T, STADIUM S
WHERE P.TEAM_ID = T.TEAM_ID AND T.STADIUM_ID = S.STADIUM_ID
ORDER BY 선수명;
OUTER JOIN
: 조인 조건
을 만족하지 않는
행들도 함께 반환
select 테이블1.칼럼명, 테이블2. 칼럼명, ...
from 테이블1, 테이블2
where 테이블2.칼럼명(+) = 테이블1.칼럼명;
oracle의 (+)
(+)
표시의 반대편
에 있는 테이블이 outer join
의 기준
테이블기준 테이블
의 모든 데이터 표시조인에 실패
한 행들의 경우 기준 테이블
은 칼럼들의 값
이 표시되고, 그 외 테이블에서 가져오는 칼럼들은 null
로 표시
--홈팀이 없는 경기장도 출력
SELECT STADIUM_NAME, A.STADIUM_ID, SEAT_COUNT, HOMETEAM_ID, TEAM_NAME
FROM STADIUM A, TEAM B
WHERE B.TEAM_ID(+) = A.HOMETEAM_ID
ORDER BY A.HOMETEAM_ID;
from절
의 조인 형태
ON조건절
의 경우 natural join 처럼 join조건이 숨어 있지 않고, 명시적으로 join 조건을 구분할 수 있으며, using조건절
이나 natural join
과 다르게 칼럼명
이 다르더라도 join조건으로 사용 가능
INNER JOIN
: 조인 조건을 만족
하는 행들만 반환
=> USING 조건절
이나 ON 조건절
을 필수적으로 사용해야 함
--where절 조인 조건
SELECT EMP.DEPTNO, EMPNO, ENAME, DNAME
FROM EMP, DEPT
WHERE EMP.DEPTNO = DEPT.DEPTNO;
--from절 조인 조건
SELECT EMP.DEPTNO, EMPNO, ENAME, DNAME
FROM EMP INNER JOIN DEPT ON EMP.DEPTNO = DEPT.DEPTNO;
NATURAL JOIN
: 두 테이블 간 동일한 이름
을 갖는 모든 칼럼
들에 대해 EQUI JOIN
수행
=> USING 조건절
, ON 조건절
, WHERE절에서 조인 조건
정의 X
=> SQL Server에서 지원X
SELECT A.DEPTNO, A.EMPNO, ENAME, B.DNAME
FROM EMP A NATURAL JOIN DEPT B;
두 테이블에서 deptno
라는 공통된 칼럼을 자동으로 인식해 조인
처리
조인에 사용된 칼럼
들은 같은 데이터 유형
이어야 하며, alias
나 테이블명
과 같은 접두사 붙일 수 없음
데이터 성격(도메인)
도 동일해야 함
-- 칼럼 순서 지정 X시 조인 기준 칼럼이 먼저 출력됨
-- 조인에 사용된 같은 이름의 칼럼을 하나로 처리
SELECT * FROM EMP NATURAL JOIN DEPT;
-- 첫번째 테이블, 두번째 테이블 순으로 데이터 출력
-- 조인에 사용된 컬럼은 별개로 표시
SELECT * FROM EMP INNER JOIN DEPT ON EMP.DEPTNO = DEPT.DEPTNO;
natural join
과 inner join
의 차이를 자세히 알아보자
-- dept_temp 테이블 생성
--oracle
create table dept_temp
as select * from dept;
--sql server
select * into dept_temp from dept;
-- update
update dept_temp
set dname='CONSULTING'
where dname='RESEARCH';
update dept_temp
set dname='MARKETING'
where dname='SALES';
-- dept_temp 출력
select *
from dept_temp;
select *
from dept a
natural join dept_temp b;
세 개의 칼럼명
이 모두 같아 위와 같이 출력되었으며, dname이 같지 않은 20, 30의 데이터는 제외
select *
from dept a join dept_temp b
on b.deptno=a.deptno
and b.dname=a.dname
and b.loc=a.loc;
같은 컬럼명이 2개씩 표현된 것을 확인할 수 있다.
using 조건절
: 같은 이름
을 가진 칼럼 중 원하는 칼럼
만 선택적으로 EQUI 조인 가능
=> sql server 지원X
SELECT *
FROM DEPT JOIN DEPT_TEMP
USING (DEPTNO);
칼럼 순서를 지정하지 않으면, using 조건절
의 기준이 되는 칼럼이 다른 컬럼보다 먼저 출력
using 조건절
은 조인에 사용된 칼럼을 하나로 처리
SELECT DEPTNO, DEPT.DNAME, DEPT.LOC, DEPT_TEMP.DNAME, DEPT_TEMP.LOC
FROM DEPT JOIN DEPT_TEMP USING (DEPTNO);
natural join
과 마찬가지로 조인 칼럼
에 대해서는 alias
나 테이블명
과 같은 접두사 X
SELECT *
FROM DEPT JOIN DEPT_TEMP
USING (LOC, DEPTNO);
loc와 deptno
가 순서대로 출력되며 조인 조건에 참여하지 않은 dname
칼럼은 2개의 칼럼으로 표시
ON조건절
은 where조건절
에 비해 분리
되어 이해하기 쉬우며, 컬럼명
이 다르더라도 조인 조건으로 사용 가능
SELECT E.EMPNO, E.ENAME, E.DEPTNO, D.DNAME
FROM EMP E JOIN DEPT D ON (E.DEPTNO = D.DEPTNO);
on조건절
의 괄호
는 옵션
from절
에 테이블
이 많이 사용될 경우 가독성이 떨어짐
SELECT E.ENAME, E.DEPTNO, D.DEPTNO, D.DNAME
FROM EMP E JOIN DEPT D ON (E.DEPTNO = D.DEPTNO)
WHERE E.DEPTNO = 30;
on조건절
에 데이터 검색 조건
을 추가할 수 있으나, where절
사용 권고
=> 아우터 조인
에서 조인 대상 제한
을 위한 목적이면, on절에 표기
SELECT E.ENAME, E.MGR, D.DEPTNO, D.DNAME
FROM EMP E JOIN DEPT D ON (E.DEPTNO = D.DEPTNO AND E.MGR = 7698);
SELECT TEAM_NAME, TEAM.STADIUM_ID, STADIUM_NAME
FROM TEAM JOIN STADIUM ON TEAM.STADIUM_ID = STADIUM.STADIUM_ID
ORDER BY STADIUM_ID;
--using 가능
SELECT TEAM_NAME, STADIUM_ID, STADIUM_NAME
FROM TEAM JOIN STADIUM
USING (STADIUM_ID)
ORDER BY STADIUM_ID;
SELECT TEAM_NAME, TEAM_ID, STADIUM_NAME
FROM TEAM JOIN STADIUM ON TEAM.TEAM_ID = STADIUM.HOMETEAM_ID
ORDER BY TEAM_ID;
--다른 이름의 칼럼으로 조인하므로 using 조건절 사용 불가
-- 사원과 dept 테이블, dept_temp의 부서명 출력
SELECT E.EMPNO, D.DEPTNO, D.DNAME, T.DNAME New_DNAME
FROM EMP E JOIN DEPT D ON (E.DEPTNO = D.DEPTNO)
JOIN DEPT_TEMP T ON (E.DEPTNO = T.DEPTNO);
-- 홈팀이 3점 이상 차이로 승리한 경기
SELECT B.STADIUM_NAME, B.STADIUM_ID,
A.SCHE_DATE, C.TEAM_NAME, D.TEAM_NAME, A.HOME_SCORE, A.AWAY_SCORE
FROM SCHEDULE A JOIN STADIUM B ON B.STADIUM_ID = A.STADIUM_ID
JOIN TEAM C ON A.HOMETEAM_ID = C.TEAM_ID
JOIN TEAM D ON A.AWAYTEAM_ID = D.TEAM_ID
WHERE A.HOME_SCORE > = A.AWAY_SCORE +3;
CROSS JOIN
: 테이블 간 조인 조건이 없는
경우 생길 수 있는 모든 데이터
의 조합
=> M*N건
의 데이터 조합 발생
SELECT ENAME, DNAME
FROM EMP CROSS JOIN DEPT
ORDER BY ENAME;
emp 테이블 14건 * dept 4건으로 56개 행 출력
SELECT ENAME, DNAME
FROM EMP CROSS JOIN DEPT
WHERE EMP.DEPTNO = DEPT.DEPTNO;
--위와 결과 같음
SELECT ENAME, DNAME
FROM EMP INNER JOIN DEPT ON EMP.DEPTNO = DEPT.DEPTNO;
cross join
의 경우 where
절에 조인 조건
을 추가할 수 있는데, 이 경우 inner join
과 같은 결과를 얻음
(+)
의 경우 where
절의 검색 조건 구분이 불명확, in
이나 or
연산자 사용시 에러, 누락된 조인 및 검색 조건 존재 시 outer join
이 아닌 inner join
으로 수행, full outer join
미지원 등의 불편함 존재
outer join
=> using 조건절
이나 on조건절
필수
LEFT OUTER JOIN
: 조인 수행 시 먼저 표기된 좌측 테이블
에 해당하는 데이터를 먼저 읽은 후, 나중 표기된 우측 테이블
에서 조인 대상
데이터를 읽어 옴
=> 조인 조건 만족하는 값 X시 우측 테이블 칼럼은 NULL값
으로 채움
--홈팀이 없는 경기장도 같이 출력
SELECT STADIUM_NAME, STADIUM.STADIUM_ID, SEAT_COUNT, HOMETEAM_ID, TEAM_NAME
FROM STADIUM LEFT OUTER JOIN TEAM ON STADIUM.HOMETEAM_ID = TEAM.TEAM_ID
ORDER BY HOMETEAM_ID;
RIGHT OUTER JOIN
: LEFT JOIN
과 반대로 우측 테이블
이 기준이 되어 결과 생성
=> OUTER
키워드 생략 가능
-- 사원이 없는 부서도 함께 출력
SELECT E.ENAME, D.DEPTNO, D.DNAME
FROM EMP E RIGHT OUTER JOIN DEPT D ON E.DEPTNO = D.DEPTNO;
FULL OUTER JOIN
: 조인 수행 시 좌측
, 우측
테이블의 모든 데이터
를 읽어 조인해 결과 생성
=> RIGHT OUTER JOIN
과 LEFT OUTER JOIN
의 결과를 합집합
으로 처리한 결과와 동일
(조인 성공 행은 한번만 표시)
=> outer 키워드 생략 가능
-- full outer 사례 만들기 위해 update
UPDATE DEPT_TEMP SET DEPTNO = DEPTNO + 20; SELECT * FROM DEPT_TEMP;
SELECT *
FROM DEPT FULL OUTER JOIN DEPT_TEMP ON DEPT.DEPTNO = DEPT_TEMP.DEPTNO;
inner join
: 양쪽 테이블에 모두 존재하는 B-B, C-C 2건 출력
left outer join
: tab1 기준으로 b-b, c-c, d-null, e-null 4건 출력
right outer join
: tab2 기준으로 null-a, b-b, c-c 3건 출력
full outer join
: 양쪽 기준으로 null-a, b-b, c-c, d-null, e-null 5건 출력
cross join
: 조인 가능한 모든 경우의 수(outer join 제외)
=> b-a, b-b, b-c, c-a, c-b, c-c, d-a, d-b, d-c, e-a, e-b, e-c 총 12건 (4*3)