Search
castle

SQL

  • Stuctured Query Language
    • 정형 데이터 구조로 정보를 조회 및 변경의 처리를 수행하는 명령어
    • TABLE 형태로 저장
  • 타입
    • 숫자(NUMBER), 문자(VARCHAR), 날짜(DATE)

주요 특징

  1. 관계형 DBMS에 접근하는 유일한 언어
  2. ANSI/ISO-SQL
  • 미국 산업 표준화 기구 (ANSI: American National Standards Institute)
    • 모든 DBMS 문법이 거의 비슷 Ex) SQL-86 , SQL-89, SQL:1999 , SQL:2008, SQL:2011, SQL:2016
  1. English-Like
  • SQL 명령어의 문법적인 구조 및 의미
  • SQL 명령어는 대-소문자를 구분하지 않는다 (Case-Insensitive)
  • 단 data - Case-sensitive
SELECT * FROM empwhere job = 'PRESIDENT';
SELECT * FROM emPwhere job = 'PRESIDENT';
SELECT * FROM EMP WHERE JOB = 'PRESIDENT';

SELECT * FROM empwhere job = PRESIDENT;
SELECT * FROM empwhere job = president;  # 다름
  1. 비절차적 언어 (Non-Procedural Language)
  • 구조적(Structured) & 집합적(Set-based) & 선언적(Declarative)
  • request(what) → server(how)

dataset

  • ERD(Entity Relationship Diagram)
    • attribute relation
  • table 간의 관계 : primary key 공유

Command

oracle document

분류 대상 구문
Query 데이터 SELECT(조회)
DML(Data Manipulation Language) 데이터 INSERT(입력), UPDATE(수정), DELETE(삭제), MERGE(INSERT+UPDATE)
TCL(Transaction Control Language) 트랜잭션 COMMIT(저장), ROLLBACK(취소), SAVEPOINT(중간 저장점)
DDL(Data Definition Language) Object CREATE(생성), ALTER(변경), DROP(Object 삭제), TRUNCATE(절삭)
DCL(Data Control Language) 권한 GRANT(부여), REVOKE(취소)
  • Query(SELECT) : 정보 조회
  • DML : modify data
  • TCL
    • COMMIT&ROLLBACK : 실행 재확인(수락하시겠습니까?)
  • DCL : 접근 권한 설정
  • null, space(공백) 등 data 포함

SELECT

  • 정렬
    • 정수 : 우측 정렬
    • 문자/날짜 : 좌측 정렬
  • 연산(산술, 논리, 함수, 날짜 등) 가능
    • DB 연산 처리 효율↑
    • 연산자 overloading(날짜 등)
  • 연산자 우선순위
    • ( ) > NOT > 비교연산자> SQL연산자 > AND > OR > 산술연산자
    • AND, OR 연산자 우선순위 주의
  • SELECT [columns] FROM [TABLE];
    • columns : ,구분

Alias

  • SELECT [columns], [[column] as [alias]], ..., FROM TABLE : Column Alias, Column Heading(lable)
    • [[column] as [alias]] : column, alias 1:1 대응
    • as, "alias names", 공백
    • "" 사용 시 공백, 특수문자 지정 가능
    • as 사용 권장
SELECT ENAME, SAL+12, SAL*12 as annual_salary FROM EMP;

SELECT ENAME, MGR Manager,SAL*12 as annual_SAL,COMM+300 "Special Bonus" FROM EMP;
-- 컬럼 Alias3가지 표현방식(공백문자, AS,“~”)중 가장 명료한 방식은?
 , ~”은 특수문자,공백문자,대소문자 구분이 필요한 경우 사용

SELECT ENAME, COMM+300 보너스, COMM+300 AS "Special Bonus" FROM EMP;

문자열 결합 연산자(||)

  • ||
  • ‘’’ → ‘
  • implicit conversion 지원
  • explicit conversion(to varchar)
    • 숫자 ↔ 날짜 conversion 미지원, $\because$ 날짜, 숫자 타입, 연산 유사
    • to_char(...), to_number(...), to_date(...)
SELECT ENAME||JOB FROM EMP;
-- | : 수직선 기호(Vertical bar), 파이프 문자 , OR 연산

SELECT DNAME||' 부서는'||LOC||' 지역에 위치합니다.' as LOC FROM DEPT;
-- ACCOUNTING 부서는NEW YORK 지역에 위치합니다.
-- 명목형 자료를 문장으로

SELECT ename||'''s JOB is '||job as job_list FROM emp;
-- SMITH's JOB is CLERK
-- 홑따옴표(') = 단일인용부호 = single quotation mark
-- Oracle DBMS 문자 데이터 표현 : 'Happy New Year'
-- SCOTT'sJOB is ANALYST vs SCOTT"sJOB is ANALYST

SELECT sal, sal*100, sal|| '00', to_char(sal)||'00' FROM EMP;
-- sal||'00' : 숫자 타입과 문자타입 결합, 결과 타입은?
-- Data type Conversion
	Implicit Conversion(암시적, 자동으로) ex) sal|| '00'
	Explicit Conversion(명시적, 수동으로) ex) to_char(sal) || '00'
-- 좋은방식의 SQL Coding은?

DUAL

sys(DBMS server) 계정 소유의 Dummy Table(실제 table x)로 function, calculation을 수행하기 위한 1x1 size table

  • local 기준이 아닌 DBMS server 기준
  • sysdate : system의 현재 date(날짜 + 시간)
    • 연산의 효율
    • 시간 기준 통일
  • data를 조회하는게 아닌 DBMS 연산을 수행
    • DBMS에 접근하기 위해서 query문 사용
  • 숫자를 ,로 구분 가능
    • type : varchar
    • 자릿수 지정 가능
desc dual

SELECT * FROM DUAL;
-- DUMMY
-- X

SELECT sysdate FROM dual; // system 현재 date(날짜와 시간)을리턴하는 함수
-- SYSDATE
-- 25/07/18
-- 

SELECT 2025*12345, to_char(2025*12345,'999,999,999'), 
to_char(2025*12345,'999,999,999') as cal FROM dual;

SELECT 2025*12345, to_char(2025*12345,'999,999'), 
to_char(2025*12345,'999,999,999,999,999') as cal FROM dual;

날짜 FORMAT

https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Format-Models.html#GUID-DFB23985-2943-4C6A-96DF-DF0F664CED96

https://docs.oracle.com/en/database/oracle/oracle-database/19/refrn/NLS_DATE_FORMAT.html#GUID-FC23EEEE-AA9F-4B3C-8CBB-888C9C0CA27F

  • FORMAT : date 표현 방식을 정의
    • to_date('date_str', 'format') : return date 형식의 data
    • to_char([date_data], 'format') : return string 형식의 data
형식 의미 예시 입력 변환 결과 특징
YYYY 4자리 연도 '1981/02/20' 1981년 정확한 4자리 연도
YY 2자리 연도 '81/02/20' 2081년 (주의) 현재 세기를 기준으로 계산
RR 2자리 연도 '81/02/20' 1981년 (스마트 해석) 1950~2049 범위 내 자동 추론
MM 월 (Month) '1981/02/20' 2월 항상 2자리
MON 월 약어 '1981/FEB/20' FEB 영문 약자 (대소문자 민감)
MONTH 월 전체 '1981/FEBRUARY/20' FEBRUARY 공백 포함, 오른쪽 정렬 가능
DD 일 (Day) '1981/02/20' 20일 2자리 정수
DY 요일 약어 '1981/02/20' FRI 요일 약자 (영문)
DAY 요일 전체 '1981/02/20' FRIDAY 공백 포함, 오른쪽 정렬 가능
HH24 24시간제 시 '13:30' 13 오후 1시
MI 분 (Minute) '13:30' 30 0~59
  • FX (format exact) : 'fx...' 정확한 형식 지정
SELECT TO_CHAR(TO_DATE('0207','MM/YY'), 'MM/YY') FROM DUAL;
SELECT TO_CHAR (TO_DATE('02#07','MM/YY'), 'MM/YY') FROM DUAL;
SELECT TO_CHAR(TO_DATE('02/07', 'fxmm/yy'), 'mm/yy') FROM DUAL;

TO_CH
-----
02/07

SELECT TO_CHAR(TO_DATE('0207', 'fxmm/yy'), 'mm/yy') FROM DUAL;
SELECT TO_CHAR(TO_DATE('0207', 'fxmm/yy'), 'mm/yy') FROM DUAL;
                       *
ERROR at line 1:
ORA-01861: literal does not match format string
  • yy : 현재 연도 앞자리 + 입력 연도
  • rr : yy보다 일반적인 연도 계산
현재 연도 끝 2자리 00~49 입력 시 앞 2자리 50~99 입력 시 앞 2자리
00~49 현재 연도 현재 연도 - 1
50~99 현재 연도 - 1 현재 연도
SELECT TO_CHAR(TO_DATE('27-OCT-98', 'DD-MON-YY'), 'YYYY') "Year" FROM DUAL;

Year
----
2098

SELECT TO_CHAR(TO_DATE('27-OCT-98', 'DD-MON-RR'), 'YYYY') "Year" FROM DUAL;

Year
----
1998
  • NLS_DATE_FORMAT : format의 기본 형식
    • NLS_DATE_FORMAT = “MM/DD/YYYY”(oracle)

  • alter session set nls_date_format ='format' : 날짜 기본 형식 변경
    • 단 현재 실행(session) 이후 초기화

WHERE

row(record) 조회하는 조건절

  • sort-circuit : X
  • ([data]) : single data
  • (([data])) : 1:1 대응

SELECT * FROM EMP WHERE DEPTNO = 10;

SELECT DEPTNO, ENAME, SAL, JOB FROM EMP WHERE SAL > 2000;
SELECT DEPTNO, ENAME, SAL, JOB FROM EMP WHERE DEPTNO = 10 AND SAL > 2000;
SELECT DEPTNO, ENAME, SAL, JOB FROM EMP WHERE DEPTNO = 10 OR SAL > 2000;

SELECT DEPTNO, SAL, JOB FROM EMP WHERE DEPTNO = 10 AND SAL > 2000 OR JOB='MANAGER';
SELECT DEPTNO, SAL, JOB FROM EMP WHERE (DEPTNO = 10 AND SAL > 2000) OR JOB='MANAGER';
-- AND > OR -> 동일
SELECT DEPTNO, SAL, JOB FROM EMP WHERE DEPTNO = 10 AND (SAL > 2000 OR JOB='MANAGER');
-- 연산자 우선순위 ? , 좋은 방식의 SQL 코딩?


SELECT DEPTNO, ENAME, SAL, JOB FROM EMP WHERE JOB = 'manager';
-- none, data case-sesitive

SELECT DEPTNO,ENAME,JOB FROM EMP WHERE 1=1;
SELECT DEPTNO,ENAME,JOB FROM EMP WHERE 1=2;
-- 1=1 : True, 1=2 : False
SELECT DEPTNO, ENAME, SAL, JOB FROM EMP WHERE (DEPTNO,JOB,MGR) = ((10,'MANAGER',7839));

NULL

데이터가 존재(미입력)하지 않는 상태, 결측치(Missing Value) 프로그램에 따라 공백 혹은 null data return. 제어, 비교, 연산 불가

  • 0 또는 공백(black space)과 다른 데이터
    • 참고 : 0(48), ‘ ‘(32), null(00)
  • is : null type 비교

  • 연산불가
-- 연산불가
SELECT 300/0 FROM dual; // divisor is equal to zero"
SELECT 300+400, 300+NULL, 300/NULL FROM dual; // NULL 연산 결과는?
SELECT ENAME, SAL, COMM, COMM+SAL*0.3 as bonus FROM EMP; // 실수하기 쉬운…해결책은….?


  • 비교불가
-- 비교불가
SELECT ENAME,SAL,COMM FROM EMP WHERE COMM > -1; // null 있는column 비교연산
SELECT ENAME,SAL,COMM FROM EMP WHERE COMM = null;
SELECT ENAME,SAL,COMM FROM EMP WHERE COMM <> null;

SELECT ENAME,SAL,COMM FROM EMP WHERE COMM is null;
SELECT ENAME,SAL,COMM FROM EMP WHERE COMM is not null;


  • 제어불가(함수에 적용 불가)
-- COMM : null data 포함 table
SELECT ENAME, length(ENAME), COMM, length(COMM) FROM EMP;
SELECT sal, comm, abs(sal-comm)+300 FROM emp;

NULL 제어 함수

  • NVL(column, value) : column 상 data의 null → value
  • DECODE(column, compare, true_value, false_value) : sql상의 if 조건문
    • column == compare ? true_value : false_value
  • count(column) : null을 제외한 column의 data 개수
  • sum(column) : null을 제외한 data의 합
SELECT COMM, NVL(COMM,0), DECODE(COMM, NULL, 0, COMM) AS NVL_SIMUL FROM EMP;
SELECT concat('Commission is ',COMM), 'Commission is '||COMM FROM EMP;--NULL 무시
select count(sal) as sal_cnt, count(comm) as comm_cnt, sum(comm) as comm_sumfrom emp;
-- 단일행 함수(Single Row Function) ex) length, abs
-- 그룹행 함수(Group Row Function) ex) count, sum

ORDER BY

sort by column

  • ASC : ascenging order, DEFAULT
  • DESC : descending order
SELECT ENAME, HIREDATE, SAL, COMM FROM EMP ORDER BY ENAME ; // 정렬방향? Default
SELECT ENAME, HIREDATE, SAL, COMM FROM EMP ORDER BY ENAME asc; // SQL 가독성

SELECT ENAME, HIREDATE, SAL, COMM FROM EMP ORDER BY HIREDATE desc; // 날짜
SELECT ENAME, HIREDATE, SAL, COMM FROM EMP ORDER BY ENAME; // column name
SELECT ENAME, HIREDATE, SAL, COMM FROM EMP ORDER BY 2; // column position
SELECT ENAME, SAL*12 as 연봉 FROM EMP ORDER BY 연봉; // column alias
SELECT ENAME, HIREDATE, SAL, COMM FROM EMP ORDER BY COMM * 12; // expression, NULL 위치
SELECT ENAME, HIREDATE, SAL, COMM FROM EMP ORDER BY COMM * 12 NULLS FIRST;

SELECT DEPTNO,JOB,ENAME FROM EMP ORDER BY DEPTNO;
SELECT DEPTNO,JOB,ENAME FROM EMP ORDER BY DEPTNO,JOB; // 조합의 순서쌍
SELECT DEPTNO,JOB,ENAME FROM EMP ORDER BY DEPTNO,JOB desc; // 차이점은?

DISTINCT

중복된 데이터를 필터링하여 조회(SELECT)

  • DISTINT, UNIQUE
SELECT JOB FROM EMP;//Row개수 만큼,
SELECT UNIQUE JOB FROM EMP;//직군 종류,Oracle
SELECT DISTINCT JOB FROM EMP;//ANSI

  • 조합 가능
SELECT DISTINCT DEPTNO,JOB FROM EMP;//중복 데이터(?)
-- 컬럼(들)의 조합의 중복 필터링
SELECT JOB FROM EMP ORDER BY JOB;
-- distinct연산 내부 알고리즘: Oracle9i:Sort,10g:Hash

  • 순차 실행

SELECT DISTINCT JOB,DISTINCT DEPTNO FROM EMP;//error, 범위?
SELECT JOB, DISTINCT DEPTNO FROM EMP;//error, 위치?

SELECT COMM FROM EMP WHERE COMMIS NOT NULL;// 4Rows
SELECT DISTINCT COMM FROM EMP;//5Rows??
-- **NULL과 DISTINCT

SQL 연산자

sql 고유 연산자

BETWEEN

하한값 - 상한값 사이의 범위 검색 연산자

SELECT ENAME,SAL,HIREDATE FROM EMP WHERE SAL between 1000 and 2000; // 숫자타입
SELECT ENAME,SAL,HIREDATE FROM EMP WHERE SAL >= 1000 and SAL <= 2000; // 차이점?
SELECT ENAME,SAL,HIREDATE FROM EMP WHERE SAL between 2000 and 1000; // 이유는?

SELECT ENAME,SAL,HIREDATE FROM EMP WHERE ENAME BETWEEN 'C' AND 'K’; -- 문자 타입

SELECT ENAME,SAL,HIREDATE FROM EMP 
WHERE HIREDATE BETWEEN '81/02/20' AND '82/12/09; // 날짜 타입, 형변환

  • 'yy/mm/dd''yyyy/mm/dd'
SELECT ENAME,SAL,HIREDATE FROM EMP
WHERE HIREDATE 
BETWEEN to_date('81/02/20','yy/mm/dd') AND to_date('82/12/09','yy/mm/dd');
// 날짜 타입, 명시적형변환, 검색이 안되는 이유는 ?

SELECT ENAME,HIREDATE,
TO_CHAR(HIREDATE,'YYYY/MM/DD'),
TO_CHAR(HIREDATE,'YYYY/MM/DD HH24:MI:SS'), // Date에서 시간정보확인
TO_CHAR(HIREDATE,'RRRR/MM/DD HH24:MI:SS'),
TO_CHAR(SYSDATE, 'YYYY/MM/DD HH24:MI:SS')// sysdate에서 시간정보확인
FROM EMP;

SELECT ENAME,SAL,HIREDATE FROM EMP
WHERE HIREDATE 
BETWEEN to_date('81/02/20', 'rr/mm/dd') AND to_date('82/12/09', 'yy/mm/dd');

SELECT ENAME,SAL,HIREDATE FROM EMP
WHERE HIREDATE 
BETWEEN to_date('1981/02/20','yyyy/mm/dd') AND to_date('1982/12/09','yyyy/mm/dd');

SELECT ENAME,SAL,HIREDATE FROM EMP
WHERE HIREDATE 
BETWEEN to_date('2081/02/20','yyyy/mm/dd') AND to_date('2082/12/09','yyyy/mm/dd');

LIKE

$\sim$정규표현식, 문자열 적용

  • char conversion
    • rvalue explicit conversion 효율적
  • wildcard
    • % : 0개 이상(*)
    • _ : 1개 (?)
SELECT ENAME FROM EMP WHERE ENAME like 'A%'; // pattern matching
SELECT ENAME FROM EMP WHERE ENAME like '_A%';
SELECT ENAME FROM EMP WHERE ENAME like '%L%E%';
SELECT ENAME FROM EMP WHERE ENAME like '%LE%';
SELECT ENAME FROM EMP WHERE ENAME like '%A%';
SELECT ENAME FROM EMP WHERE ENAME NOT like '%A%';

SELECT ENAME,HIREDATE FROM EMP WHERE HIREDATE like '81%'; // 날짜 , 암시적 형변환
SELECT ENAME,SAL FROM EMP WHERE SAL like 2%; // error, 숫자
SELECT ENAME,SAL FROM EMP WHERE SAL like '2%'; // 암시적 형변환
SELECT ENAME,SAL FROM EMP WHERE TO_CHAR(SAL) like '2%'; // 명시적 형변환

IN

list operator

  • python in과 유사
SELECT EMPNO, JOB FROM EMP WHERE EMPNO IN (7369,7521,7654);// 숫자

SELECT EMPNO, JOB FROM EMP 
WHERE EMPNO = 7369 or EMPNO = 7521 or EMPNO=7654; // 차이점 ?

SELECT EMPNO,ENAME,JOB FROM EMP WHERE JOB IN ('clerk','manager'); // 문자

SELECT EMPNO,ENAME,HIREDATE FROM EMP 
WHERE HIREDATE IN ('81/05/01','81/02/20'); // x, yyyy 형식

SELECT EMPNO,ENAME,JOB,DEPTNO FROM EMP
WHERE (JOB,DEPTNO) in (('MANAGER',20),('CLERK',20));// 다중컬럼리스트, in (1..1000)
  • ANY, ALL

DECODE, CASE

DECODE

  • 조건절(if ~ else if ~ else) 연산자
  • = 비교 연산자만 사용

SELECT DEPTNO, ENAME, DECODE(DEPTNO,10,'ACCOUNTING',20,'RESEARCH',30,'SALES','ETC')
FROM EMP
ORDER BY DEPTNO;

if deptno = 10 then 'ACCOUNTING'
else if deptno =20 then 'RESEARCH'
else if deptno =30 then 'SALES'
else 'ETC'

CASE

  • 조건절(if ~ else if ~ else) 연산자
  • DECODE 연산자 기능 확장 & 성능 향상
    • 비교/논리/SQL 연산자 사용 가능
  • SELECT [columns] CASE [column] WHEN value THEN target ... ELSE taget END ...
  • 단순 DECODE
SELECT DEPTNO,ENAME, -- Simple case
	CASE DEPTNO WHEN '10' THEN 'ACCOUNTING' // 암시적(x), 에러 원인? 수정후 실행
							WHEN 20 THEN 'RESEARCH'
							WHEN 30 THEN 'SALES'
							ELSE 'ETC'
	END AS DEPARTMENT
FROM EMP
ORDER BY DEPTNO;

SELECT DEPTNO, ENAME,
	DECODE(DEPTNO,10,'ACCOUNTING',20,'RESEARCH',30,'SALES','ETC')
FROM EMP
ORDER BY DEPTNO ;
  • 범위 분류
SELECT DEPTNO, ENAME, SAL, -- Searched case
	CASE WHEN SAL >= 4800 THEN 'HIGH' // 비교연산자
			WHEN SAL BETWEEN 3000 AND 4799 THEN 'MID' // SQL 연산자
			WHEN SAL >= 1000 AND SAL <=2999 THEN 'LOW' // 비교 & 논리 연산자
	ELSE 'Passion pay'
	END SAL_GRADE
FROM EMP
ORDER BY DEPTNO;
  • NULL 처리
SELECT DEPTNO, ENAME, COMM,
	CASE WHEN COMM >= 1000 THEN 'Great'
			WHEN COMM >= 500 THEN 'Good'
			WHEN COMM >= 0 THEN 'Bad'
	ELSE 'Dreadful’ // ELSE에서 NULL Catch
	END COMM_GRADE
FROM EMP
ORDER BY DEPTNO;

❏과제

  1. 부서별 차등 보너스를 계산하는 SQL 작성
  • 10번 부서 급여의 0.3% , 20번부서 급여의 20%, 30번 부서 급여의 10%, 나머지 모든 부서 1%
  • 부서 번호, 이름,직무,급여,보너스 출력
  • 부서별, 최고 보너스 순서로 정렬
  • 소수점 반올림
  • 컬럼헤딩 변경시 컬럼 Alias 사용
SELECT DEPTNO, JOB, ENAME, SAL, NVL(comm,0) as comm_0, (SAL+ NVL(comm,0)) as totalsal, 
	CASE DEPTNO WHEN 10 THEN 0.003*(SAL+ NVL(comm,0))
			WHEN 20 THEN 0.2*(SAL+ NVL(comm,0))
			WHEN 30 THEN 0.1*(SAL+ NVL(comm,0))
	ELSE 0.01*(SAL+ NVL(comm,0))
	END BONUS
FROM EMP
ORDER BY DEPTNO, bonus desc;
left
right

C

Contents