SQL

SQL 정리 - 1

n.han 2016. 6. 30. 19:11

====================================================

# 연결 연산자 

SELECT ename ||' is a '|| job
FROM emp ;

 ====================================================

# 리터럴 값
컬럼, 테이블이 아닌 사용자 정의의 임의의 문자, 숫자, 날짜
- 문자, 날짜는 ' '로 묶어야 함

 ====================================================

# Column Heading (열 머리글)
 - 대문자 출력.

 - 첫 글자는 문자.

 - 최대 30byte.

 - 영자, 숫자, 3가지 특수문자($,#,_)만 됨.

 - AS로 " "하면 아무거나 사용 가능.

 ====================================================

# NULL 값
 - 비어있는 상태, 값이 존재하지 않음
 - 숫자 0, 문자 공백과 다름
 - 연산 시 계산 불가능, 비교 불가능

 ====================================================
# DISTINCT
 - 중복 행 제거

 ====================================================

# 테이블 목록 확인

SELECT * FROM tab ;

 ====================================================

# 컬럼 정의 확인

DESCRIBE table_name

 ====================================================

# 비교 연산자 종류

=, >, <, >=, <=, !=, <>
IN            : 값 목록 중에 하나의 값과 같으면 검색
BETWEEN       : 범위 검색
LIKE          : 문자의 패턴 비교
IS [NOT] NULL : NULL 값 비교

문자열 비교에서 크다는 오름차순으로 정렬 시 더 뒤에 있다. 작다는 더 아래에 있다.

 ====================================================

# 문자 비교 // SCOTT과 scott은 비교할 때 분명 다르다! -- 비교 시 대소문자 차이 있음

SELECT * FROM emp
WHERE ename = 'SCOTT' ;

SELECT * FROM emp
WHERE ename = 'scott' ;

 ==================================================== 

# 날짜 비교 -- 날짜 비교시 날짜 포맷과 동일해야 함

SELECT * FROM emp
WHERE hiredate > '09-JUN-81' ;  --error


=> 따라서 비교하는 09-JUN-81을 다음과 같이 현재 Date Format로 변환해주어야 한다.

SELECT * FROM EMP

WHERE HIREDATE > TO_DATE('09-JUN-81', 'DD-MON-RR');

 ==================================================== 
# IN 연산자 -- 필드명 IN ( ... )은 각각의 OR로 풀어질 수 있다.

SELECT * FROM emp
WHERE deptno = 10
   OR deptno = 20 ;

// 위 아래 문장은 같음.

SELECT * FROM emp
WHERE deptno IN (10,20) ;

 ==================================================== 

# BETWEEN 연산자

SELECT * FROM emp
WHERE sal BETWEEN 3000 AND 2000 ;     //이거 하면 무조건 아무것도 검색이 안됨.

 ==================================================== 

# LIKE 연산자
 - 문자의 부분 패턴을 비교 (숫자와 날짜는 암시적 형변환이 발생하여 허가됨)
 - %, _ 사용 (% : 0개 이상의 문자, _ : 1개의 문자)

문자필드 LIKE 'S%' ;  // S로 시작하는 모든 문자열

문자필드 LIKE '%S' ;         // S로 끝나는 모든 문자열

문자필드 LIKE '__e' ;  // 땡땡e로 끝나는 모든 문자열(즉 이름이 무조건 3글자여야 함)

문자필드 LIKE '%A_%' ;  // 중간에 A땡이 들어간 모든 문자열

문자필드 LIKE '%A\_%' ESCAPE '\' ;  // 중간에 A_이 들어간 모든 문자열

문자필드 NOT LIKE 'S%' ;  // S로 시작하는 모든 문자열을 제외한 문자열

문자필드 LIKE '77%' ; // 77로 시작하는 모든 직원 번호 (즉, 숫자도 가능하고 ' '로 묶어줘야 함)

문자필드 LIKE '1981%' ;  

 ==================================================== 

# IS NULL, IS NOT NULL 연산자

SELECT * FROM emp
WHERE comm = NULL ;    // NULL은 = 연산을 하지 않고 모두 NULL로 처리하여 검색된 값이 없게 된다.

 ==================================================== 

# ORDER BY 절
 - ORDER BY 절이 없는 경우 정렬 상태는 보장되지 않음

SELECT * FROM emp
ORDER BY deptno DESC ;     // 내림차순

SELECT * FROM emp
ORDER BY ename ASC ;       // 오름차순. 디폴트 설정이다

SELECT empno, ename, sal * 12 salary FROM emp
ORDER BY deptno, salary ;    // 부서별로 먼저 소팅하고, 그 다음

SELECT * FROM emp
ORDER BY 8, 6 DESC ;         // select된 컬럼 중에서 8번째 컬럼은 오름차순, 6번째 컬럼은 내림차순.

====================================================

# 명시적 형 변환
 - TO_CHAR, TO_NUMBER, TO_DATE
 - 규칙 : 문자와의 변환만 형식이 맞으면 됨. / 나머지는 안됨.
   - 날짜, 숫자는 문자형으로 변환 가능
   - 형식 맞는 문자는 날짜, 숫자로 변환 가능 

     (SELECT TO_DATE('1990/06/23') FROM DUAL;)
   - 날짜 -> 숫자, 숫자 -> 날짜의 변경 불가능
     ex) '2016/06/28' => NUMBER ?
          1234        => DATE ?
====================================================

TO_CHAR(HIREDATE,'YYYY/MM/DD HH24:MI:SS'),
TO_CHAR(HIREDATE,'YYYY'),
TO_CHAR(HIREDATE,'DD Month, YYYY'),       // 05 December, 1990
TO_CHAR(HIREDATE,'fmDD Month, YYYY'),    // 위랑 같은데, 여백이 없음.
TO_CHAR(HIREDATE,'Day'),          // 해당 일이 무슨 요일인지 출력
TO_CHAR(HIREDATE,'D')             // 해당 일이 무슨 요일인지 숫자로 출력(일요일부터 1)

====================================================

 # RR과 YY의 차이점 : RR은 해당 연도의 세기정보를 가지고 있다. 하지만 YY는 단순히 해당 Date의 연도를 뒤에서 두 개 자르는 것이므로, 위에서 YY로 자르면 2080으로 정보가 들어간다.

====================================================

 # NVL(expr1, expr2) : expr1이 NULL이면, expr2로 변환해준다.

 SELECT EMPNO, ENAME, MGR,
        NVL(MGR, 'NO MANAGER')
 FROM EMP ;     

// MGR의 Data Type은 Number이기 때문에, NVL로 MGR 컬럼이 Null인 row를
   Character인 'NO MANAGER'로 변환하게 되면 같은 컬럼에 두 가지 데이터 타입이 있게    되므로 에러가 발생한다.


 SELECT EMPNO, ENAME, MGR,
        NVL(TO_CHAR(MGR), 'NO MANAGER')
 FROM EMP ;

====================================================

# DECODE, CASE 표현식  - SQL 명령문에서 IF문을 구현

- 의미 : 한 row씩 읽으면서, 조건에 맞으면  해당 값을 출력하고, 없으면 디폴트 출력

          (디폴트도 없으면 null임)

DECODE(DEPTNO, 10, SAL * 1.1  
                       , 20, SAL * 1.2
                       , 30, SAL * 1.3
                            , SAL)

CASE DEPTNO WHEN 10 THEN SAL * 1.1
                    WHEN 20 THEN SAL * 1.2
                    WHEN 30 THEN SAL * 1.3
                                   ELSE SAL END
 
CASE WHEN DEPTNO IN (10,20) THEN SAL * 1.1
        WHEN DEPTNO = 30       THEN SAL * 1.2
                                            ELSE SAL END 


SELECT MAX(DECODE(JOB, 'MANAGER', NULL

                                                   , SAL))
FROM EMP => 맞는 결과인가?

// 이 결과로 첫 글자가 가장 큰 값이 나오는데, 그 이유는 DECODE는 RETURN하는 값('MANAGER')의 데이터 형식을 따르기 때문이다. 즉, SAL의 데이터 타입이 문자가 된다.

// 따라서 실제 최대 값을 출력하고 싶은 경우 TO_NUMBER로 숫자로 데이터 타입을 변환해주어야 한다.
SELECT MAX(DECODE(JOB, 'MANAGER',

                   TO_NUMBER(NULL), SAL))
FROM EMP 


SELECT MAX( CASE WHEN JOB != 'MANAGER' // 이건 THEN 뒤에 있는 Column의 형식을 따르는 것으로 보인다.
                 THEN SAL END )
FROM EMP
WHERE DEPTNO = 30 ;

====================================================

# 날짜값 조작 시 주의 사항
// SYSDATE은 현재 년,월,일,시,분,초를 알 수 있다. 다만 현재 Date Format에 따라서 특정 정보가 보이지 않는 것처럼( 다시 말해, 저장되지 않는 것처럼) 보일 수 있다.

 

TO_CHAR(TRUNC(SYSDATE),'YYYY/MM/DD HH24:MI:SS')   // 시분초가 0으로 되어 저장된다

TO_CHAR(TRUNC(SYSDATE,'MONTH'),'YYYY/MM/DD HH24:MI:SS')  // 연, 달까지만 현재 값으로 저장되고, 나머지 일은 1로, 시분초는 0으로 초기화된다.

TO_CHAR(TRUNC(SYSDATE,'YEAR'),'YYYY/MM/DD HH24:MI:SS')   // 연도까지만 현재 값으로 저장되고, 나머지 월, 일은 1로, 시분초는 0으로 초기화된다.

TO_CHAR(ROUND(SYSDATE+1,'DAY'),'YYYY/MM/DD HH24:MI:SS')  //  SYSDATE + 1를 DAY를 기준으로 반올림한다. 즉, 월화수이면 그주의 일요일로 버림되고, 목금토이면 차주 일요일로 올림된다.

==============================================
# 여러행 함수 (그룹 함수)
- 그룹당 하나의 결과 리턴
- 데이터 타입에 따라 사용 불가능한 함수 있음
- 컬럼의 NULL은 제외하고 연산 수행

AVG(COMM) // COMM에 NULL을 제외한 것들끼리 계산.

AVG(NVL(COMM,0 // COMM의 NULL도 0으로 변환하여 계산하고 싶으면 NVL 함수 사용.
SUM(ALL DEPTNO), SUM(DISTINCT DEPTNO) // 모든 row의 deptno를 더한다; 부서 번호인 10, 20, 30만을 더한다.
FROM EMP ;

COUNT(COMM), COUNT(*)   // NULL을 제외한 COMM 컬럼의 개수; NULL을 포함한 row의 개수

==============================================
# GROUP BY 사용 시 규칙
 - GROUP BY 절에 정의된 컬럼은 SELECT 절에 없어도 된다.
 - SELECT 절에 정의된 컬럼(그룹함수 제외)은 반드시 GROUP BY 절에 정의되어야 한다.

SELECT deptno, job, SUM(sal)
FROM emp
GROUP BY deptno ;      -- error. SELECT절에 정의된 job 컬럼이 GROUP BY에 없다.

==============================================

# HAVING 절 사용
 - 그룹 함수의 조건식은 WHERE절에서 사용 불가능
 - 반드시 HAVING 절에 조건식 정의
 - 그룹함수 및 GROUP BY절에 정의된 컬럼의 조건식 정의 가능

 

SELECT deptno, SUM(sal)
FROM emp
WHERE SUM(sal) > 10000
GROUP BY deptno ;     -- error

 

SELECT deptno, SUM(sal)
FROM emp
GROUP BY deptno
HAVING SUM(sal) > 10000 ;

 

SELECT DEPTNO, SUM(SAL)
FROM EMP
GROUP BY ROLLUP(DEPTNO) ;    // 맨 마지막 하위에 DEPT에 대한 총계 값이 나온다.
==============================================

Equi     Join    : 조인 비교시 '=' 사용
Non-Equi Join : '=' 이외의 비교 연산자를 사용

Inner Join       : 조인 조건식에 만족하는 결과만 검색
Outer Join      : Inner Join 결과와 함께 한쪽 집합에만 있는 행도 추가

                    LEFT, RIGHT, FULL Outer join

Self  Join        : 동일 테이블을 이용한 조인
Cross Join       : 조인 조건 없이 연결될 수 있는 모든 경우의 수 연결

 

# Outer Join

- DEPT 테이블에 40번 부서 번호 추가 검색
SELECT *
FROM EMP E, DEPT D
WHERE E.DEPTNO (+) = D.DEPTNO  ;

 

- 양쪽 집합에 추가 행이 있다면? ANSI JOIN만 가능
# Oracle Join으로 FULL Outer join 효과를 내기 위해서는
  두번의 Outer join 진행 후 합집합 결과 검색 (중복행 제거해서)

SELECT *
FROM EMP E, DEPT D
WHERE E.DEPTNO = D.DEPTNO (+)
UNION
SELECT *
FROM EMP E, DEPT D
WHERE E.DEPTNO (+) = D.DEPTNO ;

====================================================

# Outer Join 활용

- 1981년에 월별 입사 인원 수 계산
- 입사 인원이 없는 달은 검색 불가능 !!
SELECT TO_CHAR(hiredate,'YYYY/MM') AS HIRE,
       COUNT(*) AS CNT
FROM emp
WHERE TO_CHAR(hiredate,'YYYY') = '1981'
GROUP BY TO_CHAR(hiredate,'YYYY/MM')
ORDER BY 1 ;

- Outer Join을 활용하여 12개의 월을 생성하고
  조인을 통해 결과 완성 가능

SELECT B.HIRE, NVL(A.CNT,0) AS CNT
FROM (SELECT TO_CHAR(hiredate,'YYYY/MM') AS HIRE,
              COUNT(*) AS CNT
      FROM emp
      WHERE TO_CHAR(hiredate,'YYYY') = '1981'
      GROUP BY TO_CHAR(hiredate,'YYYY/MM')) A,
     (SELECT '1981/'||LPAD(LEVEL,2,'0') HIRE
      FROM dual
      CONNECT BY LEVEL <= 12) B
WHERE A.HIRE (+) = B.HIRE
ORDER BY B.HIRE ;

====================================================

# Natural Join, Using 절 사용

Natural Join : 두 집합에 동일한 이름의 모든 컬럼을
                  자동으로 Equi Join으로 처리

 

SELECT *
FROM EMPLOYEES E, DEPARTMENTS D
WHERE E.DEPARTMENT_ID = D.DEPARTMENT_ID
  AND E.MANAGER_ID    = D.MANAGER_ID  ;       -- 32 행

SELECT *
FROM EMPLOYEES E NATURAL JOIN DEPARTMENTS D  ;  -- 32 행

 

# USING 절 사용
- 두 집합에 조인 컬럼을 지정하여 잘못된 연산 수행 제거
- Euqi Join 결과만 가능

SELECT *
FROM EMPLOYEES E JOIN DEPARTMENTS D
USING (DEPARTMENT_ID) ;

# 주의사항
- Natural Join, Using 절을 이용한 조인 수행 시
  조인 컬럼에 테이블 이름, 별칭을 이용하여 수행하면 error

EX)
SELECT *
FROM EMPLOYEES E JOIN DEPARTMENTS D
USING (D.DEPARTMENT_ID)
WHERE D.DEPARTMENT_ID IN (10,20,30,40) ;

'SQL' 카테고리의 다른 글

DML (INSERT, DELETE, UPDATE)  (0) 2016.07.11
SELECT 문장의 구성  (0) 2016.07.11
Query(SELECT)  (0) 2016.07.11
SQL의 정의  (0) 2016.07.11
SQL 정리 - 2  (0) 2016.06.30