관계형 데이터베이스, 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 명 사용 Xwhere절에 올 수 없음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)