
from 절의 서브쿼리 수식으로 사용되는 조인 릴레이션select name, course_id
from students, takes
where student.ID = takes.ID;
select name, course_id
from student natural join takes;
from 절에서 일반적으로 조인이 사용되며, where 전의 조건을 축약해서 사용 가능하다.select name, title
from student natural join takes, course
where takes.course_id = course.course_id;
select name, title
from student natural join takes natural join course;
takes), 그리고 동시에 course에도 사용하고 있기 때문이다. 먼저 학생 및 학생이 들은 과목 정보 두 개를 내추럴 조인한 뒤 이를 다시 course로 묶은 첫 번째 SQL 쿼리문이 정상적으로 작동한다.natural 키워드는 조인의 조건 중 하나다.using 키워드를 통해 정확히 어떤 어트리뷰트를 비교해야 하는지 체크할 수 있다. 이때 중복 어트리뷰트는 제거된다.select name, title
from (student natural join takes) join course using (course_id);
on을 통해서 조인되는 릴레이션에 대한 전반적인 술어 조건을 걸 수 있다.select *
from student join takes on student_ID = takes_ID;
on 조건은 ID 값이 같은 튜플끼리 매칭시킨다. 이때 중복 어트리뷰트는 삭제되지 않는다.

course natural right outer join prereq: 두 릴레이션의 공통 어트리뷰트인 course_id를 기준으로 매칭, 이때 right outer은 course 릴레이션에는 없어도 prereq에는 특정 값이 존재한다면 course 어트리뷰트가 빈다 하더라도 null을 넣고 릴레이션을 만들라는 의미.course full outer join prereq using (course_id): 두 릴레이션의 course_id 값을 조인의 기준으로 사용, 다른 릴레이션에 공통 course_id가 없더라도 빈 어트리뷰트를 null로 채우라는 의미. using 조건을 사용한 릴레이션에는 course_id라는 어트리뷰트 하나가 채워진다. on과 비교해서 알아보기.
course inner join prereq on course.course_id = prereq.course_id: course_id를 기준으로 매칭하는 데, 두 릴레이션 모두에 들어 있는 값만 표시하라는 뜻.
course left outer join prereq on course.course_id = prereq.course_id: course_id가 같은 튜플을 매칭할 때 prereq가 아니라 course를 기준으로 매칭하라는 뜻. 즉 prereq에 없다 하더라도 course에 존재하는 course_id라면 튜플을 만들고, prepreq의 어트리뷰트인 prereq_id, course_id에는 null로 채운다. 이때 on 조건을 사용한 조인 릴레이션에는 중복 칼럼이 들어갈 수 있다.
course natural right outer join prereq: 내추럴 조인이기 때문에 공통 어트리뷰인 course_id 기준 매칭, 중복 어트리뷰트 없으며 right outer이기 때문에 오른쪽의 prepreq 기준으로 course에 없어도 null로 채워진다.course full outer join prereq using (course_id): using을 사용하므로 course_id는 별도로 두 개 생기지 않는다. full outer 조인이기 때문에 매칭되지 않는 course_id라 할지라도 나머지 어트리뷰트는 자동으로 null로 채워진다. create view v as <query expression>;
create view faculty as
select ID, name, dept_name
from instructor;
// faculty 뷰 생성
select name name
from faculty
where dept_name = 'Biology';
// faculty 뷰에서 생물학 담당 강사의 이름을 조회
create view departments_total_salary(dept_name, total_salary) as
select dept_name, sum(salary)
from instructor
group by dept_name;
// departments_total_salary 뷰 생성
from에서 언급되는 릴레이션이 실제 스키마가 아니라 다른 뷰일 수도 있다는 데 주의하자materialized view라고 한다.materialized view는 갱신된 최신 정보와 맞지 않으므로 뷰 또한 업데이트해야 한다.insert into faculty
values('30765', 'Green', 'Music');
faculty뷰에서 확인 가능한 어트리뷰트는 위 쿼리문에 사용한 어트리뷰트 세 가지가 끝이지만, 실제로faculty를 만드는 데 사용한 릴레이션의 어트리뷰트는salary가 더 있다. 그렇다면faculty에 삽입한 튜플은 어떻게 될까?instructor릴레이션에도 추가가 될까?
where을 통해 들어 왔다면 기존 릴레이션 값 역시 확인해야 하기 때문이다.create view instructor_info as
select ID, name, building
from instructor, department
where instructor.dept_name = department.dept_name;
insert into instructor_info
values ('69987', 'White', 'Taylor');
where 절의 dept_name이 같다는 조건이 있어야 해당 뷰에서 나타날 수 있는데, 그것을 고려하고 있는가? 만일 Taylor가 강사에만 나타난다면 뷰에는 애초에 보일 수 없는 튜플일 것이다.create view history_instructors as
select *
from instructor
where dept_name = 'History';
insert into history_instructors
values ('25566', 'Brown', 'Biology', 100000);
where 조건 자체가 성립되지 않기 때문에 뷰 삽입 자체를 막아야 한다.다음과 같은 이슈로 인해 많은 SQL에서는 간단한 뷰(
simple views)의 업데이트만을 허용하고 있다.
from 절에 릴레이션 하나만 있어야 한다.select 절에 해당 릴레이션의 어트리뷰트만 존재해야 한다. 즉 다른 수식, aggregate 연산, distinct 키워드가 있으면 안 된다.select 절에 나와 있는 어트리뷰트는 널 값이어서는 안 된다.group by나 having 절이 없어야 한다.Commit: 트랜젝션이 수행하는 업데이트가 데이터베이스 상에 지속적으로 저장Rollback: 트랜젝션 SQL 쿼리문이 수행한 모든 업데이트가 취소concurrent)인 트랜젝션과 다른 트랜젝션은 고립동기화 문제를 해결하는 데 있어서 매우 효과적인 방법!
은행 등 중요 중요 데이터베이스라면 필수적
P가 해당 릴레이션의 모든 튜플에서 지켜졌는지 확인instructor 릴레이션에 나타난 부서 값이 Biology라면 department 릴레이션에도 동일한 값이 있어야 함. instructor의 해당 어트리뷰트 dept_name은 department를 참조하고 있기 떄문foregin key (dept_name) references department
foregin key (dept_name) references department(dept_name)
// 해당 릴레이션의 어트리뷰트 dept_name 값이 department 릴레이션에도 존재해야 한다는 의미
cascade 발생 → '폭포'처럼 해당 외래키를 참조하는 다른 릴레이션의 튜플 역시 업데이트 또는 삭제create table course (
(...
dept_name varchar(20),
foreign key (dept_name) references department
on delete cascade
on update cascade,
...);
cascade 키워드 대신 set null, set default 등을 줄 수도 있다.create table person(
ID char(10),
name char(40),
mother char(40),
father char(10),
spouse char(10),
primary key (ID),
foreign key (spouse) references person);
spouse가 person 릴레이션을 참조하고 있기 때문에 새로운 튜플을 삽입할 때 무결성 제약조건이 위반됨(person에 없는 A가 spouse이지만 person에 없는 상태이기 때문에 참조 무결성 제약 조건 위반, 삽입 불가).spouse 어트리뷰트 - null로 설정, 새로 삽입되는 person을 입력한 뒤 업데이트defer 키워드를 통해 제약조건 확인을 뒤로 미루기: (1). initially deferred - 제약 조건 검사 check를 삽입이 끝난 뒤 곧바로 실시함 (2). 트랜젝션 연산이 끝난 뒤 제약 조건 검사 check를 실시함create assertion <assertion-name> check <predicate>;
date, time, timestamp, intervalblob(binary large object), clob(character large object). 데이터 베이스는 데이터 그 자체가 아니라 일반적으로 포인터를 리턴create type을 통해 생성 가능create type Dollars as numeric(12,2);
create table department
(dept_name varchar (20),
building varchar (15),
budget Dollars);
기존 내장 데이터 타입을 통해 새로운 타입을 정의한다!
create domain을 통해 생성 가능create domain person_name char(20) not null;
create domain degree_level varchar(10)
constraint degree_level_test
check (value in ('Bachelors', 'Masters', 'Doctorate'));
create index <name> on <relation-name> (attribute);
특정 릴레이션에 색인을 만든다면 해당 쿼리문 작성 시 인덱스를 사용하게 된다!
create table student
(ID varchar (5),
name varchar (20) not null,
dept_name varchar (20),
tot_cred numeric (3,0) defaut 0,
primary key (ID));
create index studentID_index on student(ID);
select *
from student
where ID = '12345';
grant 명령어를 통해 CRUD 연산 전체에 인증 가능privilege를 통해서 특정 사용자에게 데이터베이스 조작 정도를 허용할 수 있음select: 읽기 연산 수행 가능insert: 튜플 삽입 가능update: 튜플 갱신 가능delete: 튜플 삭제 가능all privilegs: 허용 가능한 권한을 모두 허용grant <privilege list> on <relation or view> to <user list>;
사용자 리스트는 사용자 아이디, 일반(public), 특정 role일 수 있다!
grant select on department to Amit, Satoshi;
Amit, Satoshi라는 두 명의 사용자에게 department라는 릴레이션에 대한 select 권한을 부여하는 쿼리문revoke <privilege list> on <relation or view> from <user list>;
user-list가 all이면 현재 revoke를 주는 사람을 제외하고 모두 박탈create a role <name>;
grant <role> to <users>;
특정 유저에게 하나씩 권한을 할당하는 것보다, 특정 권한을 가진 그룹
role을 만드는 게 보다 효율적이다!