서브쿼리
: 메인 쿼리 내에 또 다른 쿼리문을 작성하는 것
: 서브쿼리는 괄호 안에 작성
: 주로 WHERE 절에 쓰임
: SELECT문에 작성하는 서브쿼리는 조인과 동일하며, 조인이 더 효율적
: FROM 절에서도 사용 가능
SELECT 칼럼명1, 칼럼명2 ...
FROM 테이블명
WHERE 조건문 (SELECT 칼럼명3, 칼럼명4
FROM 테이블명
WHERE 조건문);
[단일행 서브쿼리]
: 서브 쿼리의 결과가 단일 행
: 연산자 - =, <> (!=), >, >=, <, <=
[예시1]
-- comm 테이블에서 ename이 WARD인 사람의 comm이 작은 ename과 comm 조회
-- 서브쿼리로 작성
SELECT ename, comm
FROM emp
WHERE comm < (SELECT comm FROM emp WHERE ename='WARD');
-- join으로 나타낸 것
SELECT e1.ename, e1.comm
FROM emp e1 JOIN emp e2
WHERE e2.ename='WARD' AND e1.comm < e2.comm;
[예시2]
-- student, department 테이블을 이용하여 서진수 학생과 주전공이 동일한 학생들의 이름과 전공 조회
SELECT s.name, d.dname
FROM student s JOIN department d
ON s.deptno1=d.deptno
WHERE s.deptno1 = (SELECT deptno1 FROM student WHERE name='서진수');
[예시3]
-- professor, department 테이블을 이용하여 박원범 교수보다 나중에 입사한 사람의 이름, 입사일, 학과명 조회
SELECT p.name, p.hiredate, d.dname
FROM professor p
JOIN department d ON p.deptno=d.deptno
WHERE p.hiredate > (SELECT hiredate FROM professor WHERE name='박원범');
[예시4]
-- 위 예시보다 아래 예시처럼 명시적으로 주는 것이 더 많이 사용됨
-- student 테이블에서 주전공이 201 학과(전자공학과)의 평균 몸무게보다 몸무게가 많은 학생들의 이름과 몸무게 조회
SELECT s.name, s.weight
FROM student s
WHERE s.weight > (SELECT AVG(weight) FROM student WHERE deptno1='201');
-- student 테이블에서 주전공이 전자공학과인 학과의 평균 몸무게보다 몸무게가 많은 학생들의 이름과 몸무게 조회
SELECT s.name, s.weight
FROM student s
WHERE s.weight > (SELECT AVG(st.weight)
FROM student st
JOIN department d ON d.deptno = st.deptno1
WHERE d.dname = '전자공학과')
ORDER BY 2;
[예시5]
-- gogak, gift 테이블을 이용하여 노트북을 받을 수 있는 고객의 이름, 포인트 조회
SELECT go.gname, go.point
FROM gogak go
WHERE go.point > (SELECT g_start FROM gift WHERE gname='노트북');
[예시6]
-- gogak, gift 테이블을 이용하여 노트북을 받을 수 있는 고객의 이름, 포인트 조회
SELECT go.gname, go.point
FROM gogak go
WHERE go.point > (SELECT g_start FROM gift WHERE gname='노트북');
[예시7]
-- emp, dept 테이블을 이용하여 sales 부서를 제외한 나머지 부서에 속한 직원의 사번, 이름, 부서명 조회
SELECT e.empno, e.ename, d.dname
FROM emp e JOIN dept d USING(deptno)
WHERE deptno <> (SELECT deptno FROM dept WHERE dname='SALES');
[예시8] 서브쿼리 2개 이용
-- student, exam_01, hakjum 테이블을 이용하여 학점이 A0인 학생의 학번, 이름, 점수 조회
-- USING도 사용 가능
-- between 사용 가능
SELECT s.studno, s.name, e.total
FROM student s JOIN exam_01 e ON s.studno=e.studno
WHERE e.total > (SELECT min_point FROM hakjum WHERE grade='A0')
AND e.total < (SELECT min_point FROM hakjum WHERE grade='A+')
ORDER BY 3;
[예시9] 메인 쿼리의 테이블을 서브쿼리 내에서 사용
-- emp2 테이블에서 본인이 속한 부서의 평균 연봉보다 적게 받는 직원의 이름, 연봉, 부서명 조회
-- 단일행
SELECT name, pay, d.dname
FROM emp2 e JOIN dept2 d ON e.deptno = d.dcode
WHERE pay < (SELECT AVG(pay) FROM emp2 WHERE deptno=e.deptno);
[다중행 서브쿼리]
: 서브 쿼리 결과가 여러 행
: 연산자 - in, exists, > any, > any, <all, >all
: any - 하나라도 만족하면 true >> 데이터들 중 하나라도 만족하면 출력, all - 모두 만족해야 true >> 데이터 중 모든 것이 만족해야 함
[예시1]
-- emp2 테이블을 이용하여 '과장' 직급의 최소 연봉자보다 연봉이 높은 직원의 사번, 이름, 연봉 조회
-- 단일행
SELECT empno, name, pay
FROM emp2
WHERE pay > (SELECT MIN(pay) FROM emp2 WHERE position='과장');
-- 다중행
SELECT empno, name, pay
FROM emp2
WHERE pay >any (SELECT pay FROM emp2 WHERE position='과장')
ORDER BY 3;
[예시2]
-- student 테이블에서 학년별로 키가 가장 큰 학생의 이름과 학년 조회
SELECT name, grade, height
FROM student
WHERE (grade, height) IN (SELECT grade, max(height) FROM student GROUP BY grade)
ORDER BY 2;
[예시3]
-- student 테이블에서 학년이 1학년인 학생중에 몸무게가 가장 적은 학생보다 몸무게가 적은 학생의 이름, 학년, 몸무게 조회
SELECT name, grade, weight
FROM student
WHERE weight <all (SELECT weight FROM student WHERE grade=1);
[예시4]
-- emp2, dept2 테이블을 이용해 각 부서별 평균 연봉을 구하고 평균 연봉이 가장 적은 부서의 평균 연봉보다 많이 받는 직원들의 직원명, 부서명, 연봉 조회
SELECT e.name, d.dname, e.pay
FROM emp2 e JOIN dept2 d ON e.deptno=d.dcode
WHERE e.pay >any (SELECT AVG(pay) FROM emp2 GROUP BY deptno);
[예시5]
-- student, exam_01, department 테이블에서 같은 학과 같은 학년 학생의 평균 점수보다 점수가 높은 학생의 학번, 이름, 학과, 학년, 점수 조회
SELECT s.studno, s.name, d.dname, s.grade, e.total
FROM student s JOIN department d ON s.deptno1=d.deptno
JOIN exam_01 e USING(studno)
WHERE e.total >any (SELECT AVG(e1.total)
FROM student s1 JOIN exam_01 e1 USING(studno)
GROUP BY grade, deptno1)
ORDER BY s.deptno1, s.grade;
[예시6] Exists
-- student, professor 테이블에서 담당 학생이 있는 교수들의 교수번호, 교수명 조회
SELECT DISTINCT s.profno, p.name
FROM student s JOIN professor p USING(profno)
WHERE profno IS NOT NULL;
SELECT p.profno, p.name
FROM professor p
WHERE EXISTS (SELECT * FROM student WHERE profno=p.profno);
SELECT e.profno, p.name
FROM (SELECT DISTINCT profno FROM student) e JOIN professor p USING(profno);
-- student, professor 테이블에서 담당 학생이 없는 교수들의 교수번호 교수명 조회
SELECT p.profno, p.name
FROM professor p
WHERE NOT EXISTS(SELECT * FROM student s WHERE p.profno=s.profno);
[Structure Query Language]
DDL(Data Definition Language)
: 데이터 정의어(데이터베이스를 정의하는 언어)
: 데이터가 아닌 CREATE에 의해 생성된 것을 기준으로 함(즉, 데이터베이스, 테이블, 뷰, 인덱스 등의 데이터베이스 개체를 대상으로 함)
: CREATE(생성), ALTER(변경), TRUNCATE(잘라내기), DROP(삭제)
[데이터베이스 생성 및 삭제]
-- 데이터베이스 생성
CREATE DATABASE 데이터베이스명;
-- 데이터베이스 삭제
DROP DATABASE 데이터베이스명;
CREATE
[테이블 생성]
CREATE TABLE 테이블명(
칼럼명1 데이터 타입 PRIMARY KEY,
칼럼명2 데이터 타입 NOT NULL,
칼럼명3 데이터 타입 DEFAULT 값,
....,
PRIMARY KEY(칼럼명1)
);
: PRIMARY KEY
- NOT NULL(default)이면서 UNIQUE하고 유일한 것으로 칼럼과 함께 지정도 가능하고, 마지막에 작성도 가능하며, 추후 추가도 가능
: NOT NULL - NULL을 허용하지 않음
: DEFAULT 값 - 작성한 값으로 디폴트 값 지정
[기존 테이블에서 데이터 가져와 테이블 생성]
CREATE TABLE 생성할 테이블명 AS (복사할 테이블의 SELECT문 작성)
CREATE TABLE emp_sub
AS SELECT empno, ename, job, hiredate, sal FROM emp WHERE deptno=10;
[빈 테이블 생성]
CREATE TABLE 생성할 테이블명 AS (SELECT * FROM 테이블명 WHERE 거짓조건문);
CREATE TABLE emp_t AS SELECT * FROM emp WHERE 1=2;
ALTER
[이미 생성된 테이블에 칼럼 추가]
ALTER TABLE 테이블명 ADD 칼럼명 데이터 형식 및 권한 설정;
[이미 있는 칼럼 데이터 형식 변경]
ALTER TABLE 테이블명 MODIFY COLUMN 변경할 칼럼명 변경할 데이터형식;
[칼럼 삭제]
ALTER TABLE 테이블명 DROP 칼럼명;
[칼럼명 변경]
ALTER TABLE 테이블명 RENAME COLUMN 기존 칼럼명 TO 변경할 칼럼명;
[테이블명 변경]
RENAME TABLE 기존 테이블명 TO 변경할 테이블명;
[테이블 삭제]
DROP TABLE 테이블명;
[데이터 삭제]
TRUNCATE TABLE 테이블명;
DELETE FROM 테이블명 (WHERE 조건절);
- TRUNCATE는 테이블을 삭제하지는 않지만 테이블의 내용은 모두 삭제하며, 메모리까지 삭제
- DELETE는 테이블을 삭제하지 않고 모든 데이터가 삭제되지만, 메모리는 유지
[constraint(제약조건)]
- PRIMARY KEY : 동일한 데이터 및 NULL값을 허용하지 않음 (unique & not null)
- NOT NULL : NULL값이 허용되지 않음
CREATE TABLE temp(
id INT PRIMARY KEY,
name VARCHAR(20) NOT NULL
);
INSERT INTO temp VALUES(null, 'jung'); -- 에러 : id에 null 값이 들어갈 수 없음
INSERT INTO temp VALUES(1, 'jang');
INSERT INTO temp VALUES(1, 'gong'); -- 에러 : 동일한 id 생성 불가
INSERT INTO temp VALUES(2, NULL); -- 에러 : 이름에 null이 들어갈 수 없음
- UNIQUE : 동일한 데이터를 허용하지 않지만 null은 허용되며, null은 중복도 허용
CREATE TABLE temp2(
email VARCHAR(50) UNIQUE
);
INSERT INTO temp2 VALUES(null);
INSERT INTO temp2 VALUES('kosta@kosta.com');
INSERT INTO temp2 VALUES(null);
INSERT INTO temp2 VALUES('kosta@kosta.com'); -- 에러 : email 중복
- CHECK : 특정 값의 타당성을 보장하기 위한 것으로, 값의 범위를 제한. check(값의 조건 설정)
CREATE TABLE temp3(
name VARCHAR(20) NOT NULL,
age INT DEFAULT 1 CHECK(age>0)
);
-- 칼럼값을 전부 넣을 것이 아닌 경우 칼럼명 명시가 필요
INSERT INTO temp3 (name) VALUES('hong');
INSERT INTO temp3 VALUES('song', -2); -- 에러 : age>0이라는 check 조건을 만족하지 않음
INSERT INTO temp3 VALUES('song', 1);
- FOREIGN KEY : 2개 이상의 테이블의 관계를 맺는 것
더 자세히는 내일 블로깅 참고
DML(Data Manipulation Language)
: 데이터 조작어(데이터베이스 내 레코드를 조작하는 언어)
: 데이터를 기준으로 함
: INSERT(입력), UPDATE(수정), DELETE(삭제), MERGE(병합)
DCL(Data Controller Language)
: 데이터 제어어
: 데이터베이스 접근에 대한 권한을 결정하는 역할을 하는 언어
: GRANT(권한 추가), REVOKE(권한 삭제)
- 권한은 계정마다 특정 테이블에 권한을 주거나 테이블 사이의 관계에 따른 권한을 주는 등에 대한 제어
TCL(Transaction Control Language)
: COMMIT(확정-모든 작업을 정상으로 처리), ROLLBACK(취소-이전 커밋 상태로 되돌림)
: 트랜젝션 - 데이터베이스의 상태를 변화시키기 위해 수행하는 작업 단위
DQL(Data Query Language)
: SELECT(선택)
'Kosta 교육' 카테고리의 다른 글
[Day20 - DB] FK(FOREIGN KEY), DML : 데이터 조작어 (0) | 2023.09.07 |
---|---|
[이론 - DB] 데이터 모델링 (0) | 2023.09.07 |
[Day18 - DB] 날짜 함수, 숫자 함수, GROUP BY, CASE, JOIN (0) | 2023.09.05 |
[Day17 - DB] SELECT/FROM, WHERE, 문자열 함수 (0) | 2023.09.05 |
[Day17 - DB] 데이터베이스 및 DBMS 기본 (0) | 2023.09.04 |