Learn/KH정보교육원

[KH정보교육원 당산] 24일차 (SQL 집합연산자,JOIN,집계함수,HAVING,중첩질의,뷰(view),시퀀스)

Dahoon06 2021. 4. 12. 12:21
728x90
반응형

집합연산

합집합(UNION,UNION ALL)
교집합(INTERSECT)
차집합(MINUS)

 

형식 ) 
select문1 집합연산자 select문2
select문1 과 select문2 의 필드개수데이터타입이 서로 같아야함

 

 

전체 데이터

데이터

더보기

-- 부서 테이블 제거하기
DROP TABLE EMP;
-- 사원 테이블 제거하기
DROP TABLE DEPT;
-- 급여 테이블 제거하기
DROP TABLE SALGRADE;
-- 부서 테이블 제거하기
DROP TABLE EMPLOYEE;
-- 사원 테이블 제거하기
DROP TABLE DEPARTMENT;
-- 급여 테이블 제거하기
DROP TABLE SALGRADE;

-- 부서 테이블 생성하기
CREATE TABLE DEPT(
 DEPTNO NUMBER(2) CONSTRAINT PK_DEPT PRIMARY KEY,
 DNAME VARCHAR2(14),
 LOC   VARCHAR2(13) ) ;

-- 사원 테이블 생성하기
CREATE TABLE EMP( 
    EMPNO NUMBER(4) CONSTRAINT PK_EMP PRIMARY KEY,
 ENAME VARCHAR2(10),
   JOB   VARCHAR2(9),
 MGR  NUMBER(4),
 HIREDATE DATE,
 SAL NUMBER(7,2),
 COMM NUMBER(7,2),
 DEPTNO NUMBER(2) CONSTRAINT FK_DEPTNO REFERENCES DEPT);

 -- 급여 테이블 생성하기
CREATE TABLE SALGRADE(
 GRADE NUMBER,
 LOSAL NUMBER,
 HISAL NUMBER );

-- 사원 테이블에 샘플 데이터 추가하기
INSERT INTO DEPT VALUES(10, '경리부', '서울');
INSERT INTO DEPT VALUES(20, '인사부', '인천');
INSERT INTO DEPT VALUES(30, '영업부', '용인'); 
INSERT INTO DEPT VALUES(40, '전산부', '수원');

-- 부서 테이블에 샘플 데이터 추가하기
INSERT INTO EMP VALUES(1001, '김사랑', '사원', 1013, to_date('2007-03-01','yyyy-mm-dd'), 300, NULL, 20);
INSERT INTO EMP VALUES(1002, '한예슬', '대리', 1005, to_date('2007-04-02','yyyy-mm-dd'), 250,   80, 30);
INSERT INTO EMP VALUES(1003, '오지호', '과장', 1005, to_date('2005-02-10','yyyy-mm-dd'), 500,  100, 30);
INSERT INTO EMP VALUES(1004, '이병헌', '부장', 1008, to_date('2003-09-02','yyyy-mm-dd'), 600, NULL, 20);
INSERT INTO EMP VALUES(1005, '신동협', '과장', 1005, to_date('2005-04-07','yyyy-mm-dd'), 450,  200, 30);
INSERT INTO EMP VALUES(1006, '장동건', '부장', 1008, to_date('2003-10-09','yyyy-mm-dd'), 480, NULL, 30);
INSERT INTO EMP VALUES(1007, '이문세', '부장', 1008, to_date('2004-01-08','yyyy-mm-dd'), 520, NULL, 10);
INSERT INTO EMP VALUES(1008, '감우성', '차장', 1003, to_date('2004-03-08','yyyy-mm-dd'), 500,    0, 30);
INSERT INTO EMP VALUES(1009, '안성기', '사장', NULL, to_date('1996-10-04','yyyy-mm-dd'),1000, NULL, 20);
INSERT INTO EMP VALUES(1010, '이병헌', '과장', 1003, to_date('2005-04-07','yyyy-mm-dd'), 500, NULL, 10);
INSERT INTO EMP VALUES(1011, '조향기', '사원', 1007, to_date('2007-03-01','yyyy-mm-dd'), 280, NULL, 30);
INSERT INTO EMP VALUES(1012, '강혜정', '사원', 1006, to_date('2007-08-09','yyyy-mm-dd'), 300, NULL, 20);
INSERT INTO EMP VALUES(1013, '박중훈', '부장', 1003, to_date('2002-10-09','yyyy-mm-dd'), 560, NULL, 20);
INSERT INTO EMP VALUES(1014, '조인성', '사원', 1006, to_date('2007-11-09','yyyy-mm-dd'), 250, NULL, 10);

-- 급여 테이블에 샘플 데이터 추가하기
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);






 

 


합집합(union)

 => 결과값에서 중복값을 제거된 상태로 출력된다.

 

 /* student 테이블의 학생이름과 profeesor 테이블의 교수이름 합쳐 출력 */

SQL> SELECT name FROM student UNION SELECT name FORM professor;

NAME
--------------------
고희석
김광식
김우주
김정현
김태석
김현정
박광수
박철수
박철재
백태성
이태규
장민석
최성희


union all 

=> 중복 허용

/* student 테이블의 학생이름과 profeesor 테이블의 학과번호를중복 허용하여 출력 */
SQL> SELECT dept_id FROM student UNION ALL SELECT dept_id FROM professor;

DEPT_ID
--------------------
920
920
920
923
923
923
925
925
920
920
923
923
925
925


교집합(INTERSECT)

SQL> /* 컴퓨터공학과 학생들 중에서 교과목에 상관없이 학점을 'A+'받은 학생들의 학번을 검색 */

SQL> select s.stu_id
  2  from student s, department d, takes t
  3  where s.dept_id=d.dept_id AND t.stu_id=s.stu_id
  4  AND d.dept_name='컴퓨터공학과' AND t.grade='A+';

STU_ID
--------------------
1292001
1292003
=> 조건절로만 확인한 것

 

INTERSECT 사용

 

SQL> select stu_id
  2  from student s, department d
  3  where s.dept_id=d.dept_id AND dept_name='컴퓨터공학과'
  4  INTERSECT
  5  select stu_id
  6  from takes
  7  where grade='A+';

STU_ID
--------------------
1292001
1292003

 

=> 출력값이 같다.


차집합(MINUS)

SQL> /* 산업공학과 학생들 중에서 한번이라도 A+을 받지 못한 학생들의 학번 검색 */
SQL> /* 산업공학과 학생들의 학번을 검색(학생테이블, 학과테이블) */
SQL> /* 성적테이블 에서는 A+인 학생들의 학번 검색 */

 

테이블1)

SQL> select stu_id
  2  from student s, department d
  3  where s.dept_id=d.dept_id AND dept_name='산업공학과';

STU_ID
--------------------
1292301
1292303
1292305


테이블2)
SQL> select stu_id
  2  from takes
  3  where grade='A+';

STU_ID
--------------------
1292001
1292003
1292303

이 두 결과값을 빼면

뺀 값의 결과값에서(1292301, 1292305, 1292001, 1292003) 성적 비교한 후
A+가 아닌 학생들만 남게된다.


SQL> select stu_id
  2  from student s, department d
  3  where s.dept_id=d.dept_id AND dept_name='산업공학과'
  4  MINUS
  5  select stu_id
  6  from takes
  7  where grade='A+';

STU_ID
--------------------
1292301
1292305

 


JOIN

=> 두 테이블로부터 특정 조건을 만족하는 레코드들을 하나의 레코드로 결합하는 연산

즉, 테이블간의 결합


형식 ) 테이블이름1 조건식 테이블이름2
필드간의 동등비교(=)가 대부분이며 동등조인이라 함

자연조인(natural join)
=> 서로다른 테이블에서 같은 이름을 갖는 두 필드에 대한 동등 조인 중 하나의 필드를 제거하여
단순히 표현한 연산

외부조인(outer join)
=> 조인 조건에 만족되지 않은 레코드까지 검색 결과에 포함시키기 위한 방법
서로 매치되지 않는 필드에 대해서는 NULL을 입력함

종류)

왼쪽 외부조인(left outer join)
오른쪽 외부조인(right outer join)
완전 외부조인(full outer join)

 

전체 데이터

 

 

첫번째 예시를 위한 데이터

 

 

 

Class 테이블

CLASS_ID             COURSE_ID          YEAR   SEMESTER DI PROF_ID          CLASSROOM         ENROLL
-------------------- -------------------- ---------- ---------- -- -------------------- ------------------ ----------
C101-01              C101                       2012          1 A  92301                301호                      40
C102-01              C102                       2012          1 A  92001                209호                      30
C103-01              C103                       2012          1 A  92501                208호                      30
C103-02              C103                       2012          1 B  92301                301호                      30
C501-01              C501                       2012          1 A  92501                103호                      45
C501-02              C501                       2012          1 B  92502                204호                      25
C301-01              C301                       2012          2 A  92502                301호                      30
C302-01              C302                       2012          2 A  92501                209호                      45
C502-01              C502                       2012          2 A  92001                209호                      30
C502-02              C502                       2012          2 B  92301                103호                      26

Course테이블
COURSE_ID            TITLE                                        CREDIT
-------------------- ---------------------------------------- ----------
C101                 전산개론                                          3
C102                 자료구조                                          3
C103                 데이터베이스                                      4
C301                 운영체제                                          3
C302                 컴퓨터구조                                        3
C303                 이산수학                                          4
C304                 객체지향언어                                      4
C501                 인공지능                                          3
C502                 알고리즘                                          2

 

 



SQL> SELECT title, credit, year, semester
  2  FROM course, class
  3  WHERE course.course_id=class.course_id;

TITLE                                        CREDIT       YEAR   SEMESTER
---------------------------------------- ---------- ---------- ----------
전산개론                                          3       2012          1
자료구조                                          3       2012          1
데이터베이스                                      4       2012          1
데이터베이스                                      4       2012          1
인공지능                                          3       2012          1
인공지능                                          3       2012          1
운영체제                                          3       2012          2
컴퓨터구조                                        3       2012          2
알고리즘                                          2       2012          2
알고리즘                                          2       2012          2

 

왼쪽 외부조인 첫번째 방법(left outer join)

SQL> SELECT title, credit,year,semester
  2  FROM course LEFT OUTER JOIN class
  3  USING(course_id); => where course.course_id=class.course_id; 같음

=> course 테이블을 기준으로 class 테이블을 왼쪽으로 조인(결합) 시키면서 공통값은 course_id사용(USING)하겠다.

TITLE                                        CREDIT       YEAR   SEMESTER
---------------------------------------- ---------- ---------- ----------
전산개론                                          3       2012          1
자료구조                                          3       2012          1
데이터베이스                                      4       2012          1
데이터베이스                                      4       2012          1
인공지능                                          3       2012          1
인공지능                                          3       2012          1
운영체제                                          3       2012          2
컴퓨터구조                                        3       2012          2
알고리즘                                          2       2012          2
알고리즘                                          2       2012          2
객체지향언어                                      4  
이산수학                                          4

=> 객체지향언어,이산수학 year, semester null값

: class테이블에는 객체지향언어와 이산수학의 데이터을 가지고 있지 않기 때문에 NULL값으로 표현됨

 

두번째 방법

SQL> SELECT title, credit,year,semester
  2  FROM course, class
  3  WHERE course.course_id=class.course_id (+);


=> using 함수 대신에 where절에서 (+)을 이용하여 조인 시킴

TITLE                                        CREDIT       YEAR   SEMESTER
---------------------------------------- ---------- ---------- ----------
전산개론                                          3       2012          1
자료구조                                          3       2012          1
데이터베이스                                      4       2012          1
데이터베이스                                      4       2012          1
인공지능                                          3       2012          1
인공지능                                          3       2012          1
운영체제                                          3       2012          2
컴퓨터구조                                        3       2012          2
알고리즘                                          2       2012          2
알고리즘                                          2       2012          2
객체지향언어                                      4
이산수학                                          4


=> 왼쪽 조인은 왼쪽테이블의 값이 다 나온다.
그리고 오른쪽테이블에 그 값이 없으면 NULL값이 출력됨

(왼쪽테이블은 정보가 있지만 오른쪽 테이블에는 그 정보가 없기 때문에)

 

오른쪽 조인(right outer join)

SQL> SELCET title,credit,year,semester
  2  FROM course RIGHT OUTER JOIN class
  3  USING(course_id);

TITLE                                        CREDIT       YEAR   SEMESTER
---------------------------------------- ---------- ---------- ----------
전산개론                                          3       2012          1
자료구조                                          3       2012          1
데이터베이스                                      4       2012          1
데이터베이스                                      4       2012          1
운영체제                                          3       2012          2
컴퓨터구조                                        3       2012          2
인공지능                                          3       2012          1
인공지능                                          3       2012          1
알고리즘                                          2       2012          2
알고리즘                                          2       2012          2

 

=> course테이블을 기준으로 class 테이블 오른쪽으로 조인

: 객체지향언어,이산수학 이 데이터를 가지고 있지 않기 때문에 출력x

 

 

완전 외부조인(full outer join)


양쪽 테이블에서 서로 일치하는 레코드가 없을 경우
해달 레코드들로 결과 테이블에 포함시키며 나머지 필드에 대해서는 모드 null을 삽입

 

 


집계 함수(aggregate function)

=> 통계연산 기능 제공

종류 )

데이터 개수 : COUNT
합 : SUM
평균 : AVG
최대값 : MAX
최소값 : MIN

 

* SELECT절HAVING절에서 사용가능

sum avg는 숫자형 데이터타입을 갖는 필드에만 적용가능

 

count

형식)
COUNT(distinct<필드이름>) 전체 검색을 할 경우 필드이름을 (*)
=> 해당 필드에 값이 몇 개인지 출력
distinct (중복제거) 서로 구별되는 값의 개수가 필요한경우 사용
NULL값은 계산에서 제외된다.

 

 

예시 데이터)

SQL> select * from student;

STU_ID               RESIDENT_ID                  NAME                       YEAR ADDRESS              DEPT_ID
-------------------- ---------------------------- -------------------- ---------- -------------------- --------------------
1292001              900424-1825409               김광식                        3 서울                 920
1292002              900305-1730021               김정현                        3 서울                 920
1292003              891021-2308302               김현정                        4 대전                 920
1292301              890902-2704012               김현정                        2 대구                 923
1292303              910715-1524390               박광수                        3 광주                 923
1292305              921011-1809003               김우주                        4 부산                 923
1292501              900825-1506390               박철수                        3 대전                 925
1292502              911011-1809003               백태성                        3 서울                 925

 


SQL> select count(dept_id)
  2  from student;

COUNT(DEPT_ID)
--------------
             8


=> 중복값을 허용시켜서 개수를 구함



SQL> select count(distinct(dept_id))
  2  from student;
=> 중복값 제거

COUNT(DISTINCT(DEPT_ID))
-------------
            3


sum


형식)
sum(필드이름)

예시 데이터)

PROF_ID              RESIDENT_ID                  NAME                 DEPT_ID              POSITION         YEAR_EMP
-------------------- ---------------------------- -------------------- -------------------- -------------------- ----------
92001                590327-1839240               이태규               920                  교수                       1997
92002                690702-1350026               고희석               920                  부교수                     2003
92301                741011-2765501               최성희               923                  부교수                     2005
92302                750728-1102458               김태석               923                  교수                       1999
92501                620505-1200546               박철재               925                  조교수                     2007
92502                740101-1830264               장민석               925                  부교수                     2005

예) 전체 교수들의 재직연수 합

SQL> select sum(2021-year_emp)
  2  from professor;

SUM(2021-YEAR_EMP)
------------------
               110

 


avg

형식)
avg(필드이름)

예) 전체 교수들의 재직연수 평균

SQL> select avg(2021-year_emp)
  2  from professor;

AVG(2021-YEAR_EMP)
------------------
        18.3333333

 


max // min

max(필드이름)  // min(필드이름)

SQL> select max(year) from student;

 MAX(YEAR)
----------
         4

SQL> select min(year) from student;

 MIN(YEAR)
----------
         2


SQL> select name,sum(year) from student;
select name,sum(year) from student
       *
ERROR at line 1:
ORA-00937: not a single-group group function

집계함수는 결과값을 1개만 출력하고 name은 전부 출력하기 때문에 에러 발생


HAVING

: where절과 having절 group by절을 모두 함께 사용할 경우
 where절에 명시된 조건을 만족하는 레코드 검색
 group by절에 명시된 필드의 값이 서로 일치하는 레코드 끼리 그룹을 지어 집계함수 적용
 그 집계함수를 적용한 결과들 중에서 having절을 만족하는 결과만 골라 출력
즉, having을 사용하기 위해서는 반드시 group by가 사용되어야한다.

 

널의 처리 (NULL)


널(null) 검색

형식)
필드명 is null
필드명 is not null

/* A+이 아닌 학생들 번호 출력 */
SQL> SELECT stu_id
  2  FROM takes
  3  WHERE grade <> 'A+';

STU_ID
--------------------
1292001
1292001
1292002
1292002
1292002
1292003
1292301
1292303
1292303

=> where 절 
     같다 : =
     다르다 : <>

 


중첩 질의(nested query)

SQL문을 다른 SQL문 안에 중첩하여 사용하는 질의
복잡한 질의를 쉽게 표현할 수 있는 수단을 제공

내부 질의(inner query),부 질의 (subquery)
=> 내부에 포함된 SQL문

외부질의(outer query)
=> 부질의를 내부적으로 갖는 SQL문

** 부 질의는 외부 질의의 from 절이나 where 절에 위치

 

/* 301호 강의실에서 개설된 강좌의 과목명을 출력 */

첫번째 방법)
SQL> SELECT distinct title
  2  FROM course c1, class c2
  3  WHERE c1.course_id=c2.course_id
  4  AND classroom='301호';

TITLE
----------------------------------------
데이터베이스
전산개론
운영체제

두번째 방법) 
=> in을 통한 select(검색)을 한번더 한다.
SQL> SELECT title
  2  FROM course
  3  WHERE course_id in (select distinct course_id
  4  FROM class
  5  WHERE classroom='301호');

=> in대신에 not in을 사용하면 포함하지 않는값

TITLE
----------------------------------------
전산개론
데이터베이스
운영체제

 


뷰(view)

: 기존 테이블들로부터 생성되는 가상의 테이블
 테이블처럼 물리적으로 생성되는 것이 아니라 기존의 테이블들을 조합하여
 사용자에게 실제로 존재하는 테이블인 것처럼 보이게 하는것

기능) 
특정 사용자에게 테이블의 내용 중 일부를 숨실 수 있기 때문에 보안의 효과
복잡한 질의의 결과를 뷰로 만들어서 사용하게 되면 질의를 간단히 표현할 수 있다.

 

형식)
create view 뷰이름 as select문

create or replace view 뷰이름 as select문

 

or replace : 뷰이름과 같은 뷰가 이미 존재하는 경우 기존 뷰를 지우고 새로 생성(뷰를 수정할때)
select문은 뷰에 사용될 select문

 

데이터 예시)
SQL> select * from takes;

STU_ID               CLASS_ID             GRADE
-------------------- -------------------- ----------
1292001              C101-01              B+
1292001              C103-01              A+
1292001              C301-01              A
1292002              C102-01              A
1292002              C103-01              B+
1292002              C502-01              C+
1292003              C103-02              B
1292003              C501-02              A+
1292301              C102-01              C+
1292303              C102-01              C
1292303              C103-02              B+

1292303              C501-01              A+

SQL> create view v_takes as
  2  select stu_id, class_id
  3  from takes;

View created. -> V_TAKES    VIEW 테이블 확인시 table이 아닌 view라고 표기 되어있음

 

* 뷰 쪽 데이터를 수정하게 되면 원본 데이터도 같이 수정된다.
또한 뒤에 옵션을 추가할 수 있다.

 

create or replace view v_takes as
  2  select stu_id, class_id
  3  from takes
  4  with read only;
=> with read only를 추가시키므로써 이 뷰는 읽기만 가능하다.

 

뷰를 삭제할때는 테이블을 지우는것과 같다

drop view 뷰이름;

 


시퀀스(SEQUENCE)

: 오라클에서는 행을 구분하기 위해서 기본키(PK)를 두고 있다.
 기본키는 중복된 값을 가질 수 있으므로 항상 유일한 값을 가져야 하고,
 기본키가 유일한 값을 갖도록 사용자가 직접 값을 생성해내려면 불편하기 때문에 시퀀스를 사용

시퀀스는 테이블 내의 유일한 숫자를 자동으로 생성하는 자동번호 발생기이므로
시퀀스를 기본키로 사용하게 되면 사용자의 부담을 줄일 수 있다.
ex) 게시판에 글번호 같은거 -> 자동으로 증가시켜줌

 

형식)
create sequence 시퀀스이름 옵션;

 

옵션)

start with n

=> 시퀀스 번호의 시작 값 지정 ex) 만약 1부터 시작되는 시퀀스를 생성하려면 start with 1;

increment by n

=> 연속적인 시퀀스 번호의 증가치를 지정할 때 ex) 1씩 증가 increment by 1;

maxvalue n 또는 nomaxvalue n

 => 시퀀스가 가질 수 있는 최대값 지정 
nomaxvalue를 지정하게 되면 ascending 순서일 경우 1027제곱, descending일경우 -1

minvalue n 또는 nominvalue n

=> 시퀀스 최소값 지정
ascending  1 descending일경우 1026제곱


cycle 또는 nocycle

=> 지정된 시퀀스값이 최대값까지 증가 완료되면 다시 start with 옵션에 지정한 시작 값에서 시퀀스 시작
nocycle : 증가가 완료되면 에러발생시킴

cache n 또는 nocache

 => 메모리상의 시퀀스 값을 관리하도록 하는것(기본20)
 nocache는 원칙적으로 메모리상에서 시퀀스를 관리하지 않는다.

 

 

삭제)

drop sequence 시퀀스명;

 

 

currval : 시퀀스의 현재값을 알아내기 위해 사용(반드시 nextval가 먼저 실행되어야만 currval값이 나온다.)
nextval :다음값을 알아내기 위해 사용(즉, 해당 시퀀스의 값을 증가시키고 싶을때)

사용하기 위해서 
 서브 쿼리가 아닌 select문
 insert문의 select절
 insert 문의 value절
 update문의 set

사용할수 없는 경우
 view의 select절
 distinct 키워드가 있는 select문
 group by,having,order by 절이 있는 select문
 select,delete,update의 서브 쿼리
 create table, alter table 명령의 default값

nextval로 새로운 값 생성
select 시퀀스명.nextval from dual;

SQL> select se_test.nextval from dual;

   NEXTVAL
----------
        10

현재의 값을 알아내기 위해 currval
select 시퀀스명.currval from dual;
SQL> select se_test.currval from dual;

   CURRVAL
----------
        10


** dual은 실제로 존재하지 않는 테이블로 값을 미리 확인하기 위한 가상의 테이블

 

 

시퀀스 조회

SQL> select sequence_name,
  2  min_value,
  3  max_value,
  4  increment_by,
  5  cycle_flag
  6  from user_sequences;

 

출력값)

SEQUENCE_NAME               MIN_VALUE  MAX_VALUE INCREMENT_BY CY
---------------------------------------- ---------- ---------- ------------ --
EMP_ESQ                                     1     100000            1 N
SE_TEST                                       1 1.0000E+28           10 N


예제)
사원번호를 생성하는 시퀀스 객체를 생성하여 이를 기본키로 사용하는 사원 테이블-> 사원번호에 사용
시작값이 1이고 1씩 증가하며 최대가 100000 이 되는 시퀀스 emp_seq생성


테스트 테이블)

SQL> create table emp01(
  2  empno number(4) primary key,
  3  empme varchar(10),
  4  hiredate date
  5  );


SQL> select * from emp01;

     EMPNO EMPME                HIREDATE
---------- -------------------- --------
         1 ONE                 21/04/12
         2 TWO                   21/04/12
         3 THREE                 21/04/12
         4 FOUR                  21/04/12
         5 FIVE                 21/04/12

 

시퀀스를 사용하여 데이터 삽입
SQL> insert into emp01
  2  values(emp_seq.nextval,'ONE',sysdate);


728x90
반응형