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으로 한다.
- MySQL을 켤 때 autocommit이 자동으로 켜지는데 이것을 끄는 방법이다.
질문한 내용이나 어려웠던 점 메모
1. 그룹화
- 그룹화를 하면 select에 그룹화 하지 않은 칼럼을 적을 수 없다는 것을 자꾸 까먹는다.
728x90
'프로그래밍 > 수업일지' 카테고리의 다른 글
수업일지 28일차 (23/10/30) - MySQL (1) | 2023.10.30 |
---|---|
수업일지 27일차 (23/10/27) - MySQL (1) | 2023.10.27 |
수업일지 25일차 (23/10/25) - MySQL (0) | 2023.10.25 |
수업일지 24일차 (23/10/24) - MySQL (0) | 2023.10.24 |
수업일지 23일차 (23/10/23) - MySQL (3) | 2023.10.23 |