728x90

 

수업내용 정리 (MySQL)

 

1. Join

더보기
select*from dept;	-- 부모 테이블 1개
select*from emp;	-- 자식 테이블 n개(여러개 가능)
select*from salgrade;
  • join: 두 개 이상의 테이블을 행끼리 결합하는 DB의 꽃

 

  • inner(내부) join: 양 쪽(테이블) 모두에 값이 있는 행 반환(not null)
  • 기본이 inner join이기 때문에 'inner' 생략 가능!
  • 모호성(ambiguous)에 주의할 것! 테이블명에 알리어스(as)를 넣어 별칭을 지어주기.
  • 만족하는 모든 행을 결합(join)한다.

 

-- 표준(ANSI) SQL 조인
select * from dept D
join emp E
on D.deptno=E.deptno  -- 조인조건	/ 동일조인
where JOB='CLERK';	-- 일반조건
  • 표준(ANSI) SQL 조인
  • join [join 할 테이블]
  • on [join 할 조건]

 

-- 비표준 SQL 조인
select * from dept D, emp E
where D.deptno=E.deptno;

select * from dept D, emp E
where D.deptno=E.deptno and job='CLERK';
  • join을 적지 않고 join하는 방법
  • from에 테이블을 여러개 적고, join 조건을 where절에 적는다.
  • 밑의 코드는 where절에 join조건과 일반 조건이 함께 들어있다. where [join 조건] and [일반 조건]

 

 

 예제 ㄱ

-- 테이블 2개 조인
select e.ename, e.sal, concat(s.grade, '호봉') grade
from salgrade s
join emp e on e.sal between s.losal and s.hisal;	-- 비동일 조인(>= <=)
-- 테이블 3개 조인
select* from dept d
join emp e on d.deptno=e.deptno
join salgrade s on e.sal between s.losal and s.hisal;
-- 3번 
select e.ename, e.sal, s.grade, s.stdsal from emp e
join salgrade2 s on truncate(e.sal,-3)=truncate(s.stdsal,-3);

 

 

  • 인라인뷰(view): from절에 서브쿼리가 들어간 것
  • 하드디스크가 아닌 메모리 상에서만 존재하는 논리적인 테이블
  • 인라인끼리 혹은 내/외부 조인과도 같이 조인이 가능하다.
-- 10번 부서와 20번 부서 사원 중에서 직급이 같은 사원들의 이름, 부서번호, 직급을 검색 
select e1.job, e1.deptno, e1.ename, e2.deptno, e2.ename
from (select ename, deptno, job from emp where deptno=10) e1
join (select ename, deptno, job from emp where deptno=20) e2
where e1.job=e2.job;

 

 

select e.empno '사원번호', e.ename '사원 명', e.mgr '상사번호', m.ename '상사'
from emp e join emp m on e.mgr=m.empno order by e.empno;	-- 상사가 없는 경우 검색되지 않음
  • self join: 내부 조인. 같은 테이블끼리 join한다.
  • 해당 코드는 상사가 없는 경우엔 출력되지 않는다.

 

select e.empno '사원번호', e.ename '사원 명', e.mgr '상사번호', m.ename '상사'
from emp e left join emp m on e.mgr=m.empno order by e.empno;
  • 잉여 데이터가 있는 경우에도 출력할 수 있는 Left / Right Join
  • Left / Right outer join: 외부 조인. 반대쪽에 데이터가 있든 없든(null), 선택된 방향에 있으면 출력 - 행 수 결정 (Left join: 오른쪽에 잉여데이터 / Right join: 왼쪽에 잉여데이터)
  • 중간에 있는 outer은 생략이 가능하다.
  • 해당 코드는 상사가 없는 경우에도 출력이 된다.

 3번 예제에 쓰인 테이블 ㄱ 

더보기
drop table salgrade2;
create table salgrade2(
	grade int  primary key,	-- 기본 키
	stdsal int
);	-- create end
select*from salgrade2;	-- 확인 
insert into salgrade2(grade, stdsal) values(1, 0);	-- 값 집어넣기 / 0~999 1호봉
insert into salgrade2(grade, stdsal) values(2, 1000);	-- 1000~1999
insert into salgrade2(grade, stdsal) values(3, 2000);	-- 2000~2999
insert into salgrade2(grade, stdsal) values(4, 3000);	
insert into salgrade2(grade, stdsal) values(5, 4000);	
insert into salgrade2(grade, stdsal) values(6, 5000);	-- 5000~5999

 

 문제 ㄱ 

더보기
  • 문제
-- 1) comm을 받는 사원의 부서명, 부서위치, 이름, 커미션(comm) 검색
-- 2) 'dallas'(부서위치)에서 근무하는 사원 부서번호, 부서명, 이름, 직급 검색
-- 3) 'ward'(사원이름)의 부서이름과 이름 검색
-- 4) 사원이름, 급여, 급여등급 검색
-- 5) 부서명, 사원이름, 급여등급 검색
-- 6) 부서별 부서이름, 최소급여, 최대급여, 평균급여 검색
-- 7) 부서 내에서 직급별 부서번호, 부서명, 직급, 평균급여, 인원수 검색

 

 

  • 풀이
-- 1) comm을 받는 사원의 부서명, 부서위치, 이름, 커미션(comm) 검색
select d.dname, d.loc, e.ename, e.comm from dept d
join emp e on d.deptno=e.deptno where ifnull(comm,0)<>0;
  • 부서명, 부서위치, 이름, 커미션은 검색했으나 comm을 받는 사람만 출력하는 것에서 실패하고 시간이 끝났다.
  • 부서명, 부서위치가 한 테이블, 사원이름, 커미션이 한 테이블로 각 두 테이블이 있으니 join을 했다.
  • join 조건은 두 테이블 모두 동일하게 가지고 있는 deptno
  • comm을 받는 사원이 조건이므로 where절에 comm이 null이 아닐 때라는 조건을 준다.
  • ifnull(comm,0)<>0은 comm<>0으로도 변경이 가능하다.

 

-- 2) 'dallas'(부서위치)에서 근무하는 사원 부서번호, 부서명, 이름, 직급 검색
select d.deptno, d.dname, e.ename, e.job from dept d
join emp e on d.deptno=e.deptno where d.loc='dallas';
  • 부서명은 dept 테이블에 있고 / 사원이름, 사원직급은 emp 테이블에 있고 / deptno는 두 테이블 모두에 있으므로 dept 테이블과 emp 테이블을 join해주면서 deptno를 join 조건으로 줬다.
  • 일반 조건으로는 부서위치가 'dallas'인 조건이 있으므로 dept 테이블에 있는 loc(부서위치)가 'dallas'인 것만 이라는 조건을 준다.

 

-- 3) 'ward'(사원이름)의 부서이름과 이름 검색
select d.dname, e.ename from dept d join emp e on d.deptno=e.deptno where e.ename='ward';
  • 부서명은 dept 테이블, 사원 이름은 emp 테이블에 있으므로 두 테이블을 join해주고, 조건은 동일하게 가지고 있는 칼럼인 deptno를 준다.
  • 'ward'의 부서명과 이름을 검색하라고 했으니 emp 테이블에 있는 ename의 값이 'ward'인 것만 이라는 조건을 준다.

 

-- 4) 사원이름, 급여, 급여등급 검색
select e.ename, e.sal, s.grade from emp e join salgrade s on e.sal between s.losal and s.hisal;
  • 사원이름은 emp 테이블, 급여등급은 salgrade 테이블에 있으므로 두 테이블을 join해준다.
  • join 조건으로는 emp 테이블에 있는 sal이 salgrade 테이블에 있는 losal과 hisal의 사이일 경우로 준다.

 

-- 5) 부서명, 사원이름, 급여등급 검색
select d.dname, e.ename, s.grade from dept d
join emp e on d.deptno=e.deptno join salgrade s on e.sal between s.losal and s.hisal;
  • 부서명, 사원이름, 급여등급이 각 다른 테이블에 있기 때문에 각 테이블을 모두 join해준다.
  • join 조건은 dept에 emp를 join할 때는 deptno가 동일할 경우로 주고, salgrade를 join할 때는 emp의 sal이 salgrade의 losal과 hisal의 사이일 경우로 준다.

 

-- 6) 부서별 부서이름, 최소급여, 최대급여, 평균급여 검색
select d.dname '부서명', min(e.sal) '최소급여', max(e.sal) '최대급여', round(avg(e.sal),2) '평균급여'
from dept d join emp e on d.deptno=e.deptno
group by d.deptno order by d.dname;
  • 부서명은 dept 테이블, 나머지는 emp 테이블에서 구하면 되기 때문에 dept 테이블과 emp 테이블을 join해준다.
  • join 조건은 deptno가 동일할 경우로 준다.
  • 최소 급여, 최대 급여, 평균 급여 값은 각 min, max, avg 함수를 사용하여 구한다.

 

-- 7) 부서 내에서 직급별 부서번호, 부서명, 직급, 평균급여, 인원수 검색
select d.deptno '부서번호', d.dname '부서명', e.job '직급',
	round(avg(e.sal),2) '평균급여', count(e.job) '인원수'
from dept d join emp e on d.deptno=e.deptno group by e.deptno;

select round(avg(e.sal)) '평균급여', concat(count(*), '명') '인원 수', d.deptno, d.dname, e.job
from dept d join emp e on d.deptno=e.deptno
group by d.deptno, e.job, d.dname;
  • 위에 코드가 내가 풀다가 실패한 코드이고, 밑에 코드가 선생님이 풀이해주신 코드이다.
  • 내가 코드를 짤 때 그룹으로 묶을 것을 적게 줘서 오류가 났었다.
  • 우선 필요한 테이블인 dept와 emp를 join해주고 조건은 두 테이블 모두에 있는 deptno가 동일할 경우로 준다.
  • 그룹화를 해야 하는데 select에 여러 칼럼을 적었으므로 적은 칼럼을 모두 group by에 적는다. (SQL에선 d.dname은 그룹으로 안 묶어도 실행된다. Oracle에서는 안 됨!)

 

 

-- 문)
-- 본인의 사원 이름, 부서번호를 검색하고,
-- 같은 부서의 동료사원의 사원이름, 부서번호를 검색하시오
-- 이름순으로 오름정렬하시오
-- 실행예
-- 본인 부서번호 동료 부서번호
-- allen 30 blake 30
-- allen 30 james 30
-- ...
-- blake 30 allen 30
select e.ename '본인', e.deptno '부서번호', d.ename '동료', d.deptno '부서번호'
from emp e join emp d on e.deptno=d.deptno where e.ename<>d.ename order by e.ename, d.ename;
  • 같은 테이블(emp) 내의 값이 필요하므로 self join을 해준다.
  • join 조건은 같은 부서의 동료 사원이 필요하므로 deptno로 주고, 본인이 나오면 안 되기 때문에 일반 조건에 첫번째 ename과 두번째 ename이 같을 경우를 제외해준다.
  • 이름순으로 오름정렬하라고 했기 때문에 order by에 첫번째와 두번째 ename을 모두 적어준다.

 

 

2. 자료형

더보기
  • 전부 외우지 않아도 됨! 몇가지만 좀 알고 있기!
  • 선생님이 주신 PPT에서 긁어왔다.

 

  • 숫자 자료형
자료형 바이트 SIGNED UNSIGNED
TINYINT 1 -128 ~ 127 0 ~ 255
SMALLINT 2 -32,768 ~ 32,767 0 ~ 65,535
MEDIUMINT 3 -8,388,608 ~ 8,388,607 0 ~ 16,777,215
INT 4 -2,147,483,648 ~ 2,147,483,647 0 ~ 4,294,967,295
BIGINT 8 -9223372036854775808
~ 9223372036854775807
0 ~ 18446744073709551615

 

  • 문자 자료형
자료형 설명 차지하는 바이트 최대 바이트
CHAR( s ) s만큼 고정 사이즈 (스페이스로 채움) s (고정값) 255
VARCHAR ( s ) 가변 사이즈 S이 0~255 이면 문자길이+1byte,
~ 65,535 이면 문자길이+2byte
65,535
자료형 최대 바이트 크기
TINYTEXT 255
TEXT 65,535
게시글 또는 신문기사 같은 긴글 (자주 검색시 varchar보다 느림)
MEDIUMTEXT 16,777,215
LONGTEXT 4,294,967,295

 

  • 시간 자료형
자료형 설명 비고
DATE YYYY-MM-DD 3 Byte, 1000-01-01 ~ 9999-12-31
TIME HHH:MI:SS HHH: -838 ~ 838까지의 시간
DATETIME YYYY-MM-DD HH:MI:SS 8 Byte, 입력된 시간을 그 값 자체로 저장
1000-01-01 00:00:00 ~ 9999-12-31 23:59:59
TIMESTAMP YYYY-MM-DD HH:MI:SS 4 Byte, MySQL이 설치된 컴퓨터의 시간대를 기준으로 저장
1970-01-01 00:00:00 ~ 2037-01-19 03:14:07
  • datetime: 국내 서비스에 적합
  • timestamp: 국제 서비스에 적합

 

 

3. 테이블

 3-1) 생성 ㄱ 

더보기
drop table if exists member;
create table member(
	M_id int auto_increment primary key,
	M_nick varchar(20) unique not null,
	M_name varchar(20) not null,
	M_age tinyint unsigned default 0 not null,
	M_birth date default (current_date) not null 
);
desc member;
select*from member;
  • 테이블을 만들기 전, 테이블이 이미 있을 수 있으므로 테이블이 존재한다면, 삭제한다는 코드를 추가한다. (drop table if exists)
  • desc member: 테이블 구조를 확인한다.
  • select*from member: 테이블에 있는 모든 칼럼과 데이터를 확인한다.

 

  • current_date / curdate는 아직 잘 모르는 코드

 

  • 생성 시 제약
  • auto_increment: 새 행 생성 시마다 자동으로 1씩 증가 (1부터 시작)
  • primary key: 중복 입력이 불가능하고, null(빈 값)이 불가능하다. 테이블에 하나만 존재할 수 있다.
  • unique: 중복 입력이 불가능하다.
  • not null: null(빈 값) 입력이 불가능하다.
  • unsigned: (숫자일시) 양수만 입력이 가능하다.
  • default: 값 입력이 없을 시 기본 값을 넣는다.

 

 3-2) 추가 ㄱ 

더보기
  • DML) insert
insert into member(M_id, M_nick, M_name, M_age, M_birth)
			values(null, '1st', '첫번째친구', 10, '2023/10/26');
insert into member(M_nick, M_name, M_age, M_birth)
			values('2nd', '두번째친구', 10, curdate());
insert into member(M_nick, M_name, M_birth)
			values('3rd', '세번째친구', now());
insert into member values(null, '4th', '네번째친구', default, default);
insert into member values(null, '5th', '다섯번째친구', default, default);
  • 테이블 이름 뒤 괄호 안에 칼럼을 적고, values 뒤 괄호에는 앞서 적은 칼럼의 순서대로 데이터를 입력한다.
  • id는 자동으로 입력이 되므로 null 값을 넣어도 알아서 값이 입력된다.
  • 테이블 이름 뒤에 괄호 없이 바로 values가 와도 테이블을 생성할 때 입력한 칼럼 순으로 데이터를 입력해도 문제없다.
  • M_age와 M_birth는 default 값이 있었기 때문에 default로 입력하면 default 값이 자동으로 입력된다.

 

 3-3) 업데이트/수정 ㄱ 

더보기
  • DML) update
update member set M_name='n번째친구';		-- 1
update member set M_name='n번째친구' where M_id=1;	-- 2
-- update member set M_age+=10;	-- 3
update member set M_age=M_age+10 where M_id=3;	-- 4

-- 첫번째 나이 10% 증가
update member set M_age=M_age*1.1 where M_id=1;
  • 1번 코드처럼 작성하면 member 테이블에 있는 M_name은 모두 'n번째친구'로 데이터가 바뀌어버린다.
  • 2번 코드처럼 where절에 조건을 줘서 바꿔줘야 한다.
  • 3번 코드처럼 자바에서 사용하던 += 연산은 불가능하다. 10을 더하고 싶다면 4번 코드처럼 작성해야 한다.
  • 마지막 코드는 %를 사용하지 못하기 때문에 곱하기(*)를 이용하여 계산해주어야 한다.

 

  • where절에서 조건을 줄 때 primary key로 주는 것이 바꾸려는 안전하게 데이터만 바꿀 수 있고, 에러가 나지 않을 수 있다. (중복값이 있을 수 있기 때문에)
  • 한 번에 여러 값을 변경할 수도 있다.

 

 3-4) 삭제 ㄱ 

더보기
  • DML) delete
delete from member;
delete from member where M_id=5;
  • 위 코드처럼 작성하면 member 테이블에 있는 모든 데이터가 삭제된다.
  • where절에 삭제할 데이터 조건을 주어야 한다.

 

 3-5) 제약조건 설정 ㄱ 

더보기
drop table if exists board;
create table board(
	B_no int auto_increment,
	B_title varchar(100) not null,
	B_contents varchar(10000) not null,
	B_nick varchar(20) not null,
	B_date datetime default current_timestamp,
	-- 테이블 단ㄱ 
	primary key(B_no),
	constraint UQ_B_Nick unique(B_nick)
);
  • 제약 조건은 테이블의 단에 설정한다. (칼럼을 설정하면서 할 수도 있다.)
  • 제약 조건을 이름으로 설정하면 나중에 다시 제약 조건을 재설정할 수 있게 된다.
  • primary key는 이름을 설정할 수 없다. (Oracle에서는 가능)

 

-- 제약조건 삭제
alter table board drop constraint UQ_B_Nick;
alter table board drop primary key;		-- 기본키 삭제
  • 설정한 제약 조건 이름을 적어야 한다.
  • 기본 키인 primary key는 삭제할 수 있지만, auto_increment 설정 시 삭제할 수 없다.

 

-- 제약조건 추가
alter table board add constraint UQ_B_Nick unique(B_nick);
alter table board add primary key(B_no);
  • 설정할 제약 조건과 제약 조건 이름을 적는다.
  • primary key도 가능

 

-- 제약조건 확인
select*from information_schema.table_constraints;
  • 설정해둔 제약 조건들을 확인할 수 있다.

 

 

4. commit / rollback

더보기
  • commit: 작업 완료 / 하드디스크에 데이터를 저장
  • rollback: 가장 최근에 commit한 상태로 돌아감 (ctrl + z가 아님!)
  • 기본적으로 autocommit이 설정되어있기 때문에 해제해주어야 한다.
  • DML(데이터 조작어: insert, update, delete)만 적용한다.

 

select @@autocommit;			-- auto commit 확인용
  • autocommit이 켜져있다면 1, 아니라면 0이 출력된다.

 

set autocommit = 1;		-- autocommit 설정
set autocommit = 0;		-- autocommit 해제
  • autocommit을 켜려면 1, 아니라면 0으로 한다.

 

autocommit 완전 끄기
  • MySQL을 켤 때 autocommit이 자동으로 켜지는데 이것을 끄는 방법이다.

 

 


 

질문한 내용이나 어려웠던 점 메모

1. 그룹화

  • 그룹화를 하면 select에 그룹화 하지 않은 칼럼을 적을 수 없다는 것을 자꾸 까먹는다.

 


728x90