학교
DB04 - SQL
아젠다
- 구조적 쿼리 언어(SQL)
- SQL 데이터 조작 언어(DML)
- SELECT, FROM, WHERE
- NULL 값
- 집합 연산
- 문자열 연산, 정렬
- 집계 함수, 집계
- SQL 데이터 정의 언어(DDL) -- 다음 수업에 진행
구조적 쿼리 언어(SQL)
1. SQL: 구조적 쿼리 언어
1) 관계형 데이터베이스를 설명하고 조작하는 데 사용되는 주요 언어이다.
2) 매우 고급 언어이다.
(1) "어떻게 할 것인지"가 아니라 "무엇을 할 것인지"를 말한다.
(2) SQL은 데이터 조작 세부 사항을 지정하지 않는다.
(3) DBMS가 쿼리를 실행하는 "최선의" 방법을 결정한다(figure out).
- 이를 "쿼리 최적화(optimization)"라고 한다.
3) SQL의 두 가지 측면
(1) 데이터 정의(definition): 데이터베이스 스키마를 선언하기 위한 것(DDL)
(2) 데이터 조작(manipulation): 데이터베이스에 대한 질문을 하거나 데이터베이스를 수정하기 위한 것(DML)
SQL 구성 요소
- DML - 데이터베이스에서 정보를 쿼리하고, 튜플을 삽입하고, 삭제하고, 수정하는 기능을 제공한다.
- 무결성 - DDL에는 무결성 제약 조건을 지정하는 명령이 포함되어 있다.
- 뷰 정의 - DDL에는 뷰를 정의하는 명령이 포함되어 있다.
- 트랜잭션 제어 - 트랜잭션의 시작과 종료를 지정하는 명령이 포함되어 있다.
- 임베디드 SQL 및 동적(dynamic) SQL - SQL 문이 일반 프로그래밍 언어에 어떻게 삽입될 수 있는지 정의한다.
- 권한(Authorization) - 관계 및 뷰에 대한 접근 권한(access rights)을 지정하는 명령이 포함되어 있다.
- Access control List (ACL)
간단한 역사
1. IBM SEQUEL(구조적 영어 쿼리 언어)은 시스템 R 프로젝트의 일환으로 개발되었다(챔벌린과 보이스, 1970년대 초).
1) 이후 u되었다.
2) 시스템 R → 시스템/38(1979), SQL/DS(1981), DB2(1983)
2. Relational Software, Inc.는 VAX 컴퓨터용 SQL의 첫 상업적(commercial) 구현인 Oracle V2를 출시했다.
1) Relational Software, Inc.는 현재 오라클 기업이다.
3. ANSI와 ISO가 SQL을 표준화했다(standardized):
1) SQL-86, SQL-89, SQL-92, SQL:1999, …, SQL:2011, SQL:2016(현재)
2) SQL-92는 대부분의 데이터베이스 시스템에서 지원된다.
SQL 데이터 조작 언어
1. SQL 데이터 조작 언어(DML)는 데이터베이스를 쿼리(질문하기)하고 수정할 수 있게 해준다.
실행 예제
1. 관계(테이블): instructor, teaches

기본 쿼리 구조
1. 일반적인 SQL 쿼리는 다음과 같은 형식을 가진다:
SELECT A1, A2, ..., An
FROM r1, r2, ..., rm
WHERE P- Ai는 속성을 나타낸다.
- Ri는 관계를 나타낸다.
- P는 술어이다.
2. SQL 쿼리의 결과는 관계이다.
SELECT 절 - (1)
1. SELECT 절은 쿼리 결과에서 원하는(desired in) 속성을 나열한다.
1) 관계 대수의 프로젝션(projection)∏ 연산에 해당한다.
2. 예시: 모든 강사의 이름 찾기
SELECT name FROM instructor;- From : Input relation
참고
1. SQL 이름은 대소문자를 구분하지 않는다.
1) 예: Name ≡ NAME ≡ name
2) SQL 명령어(SELECT, FROM, WHERE 등)는 대문자로 작성한다(관례(convention)에 불과하다).
3) MySQL에는 lower_case_table_names라는 옵션 플래그가 있다.
(1) 링크: MySQL Identifier Case Sensitivity
SELECT 절 - (2)
1. SQL은 관계와 쿼리 결과 모두에서 중복을 허용한다.
1) ALL 키워드는 중복이 제거되지 않아야 함을 지정한다.
SELECT ALL dept_name
FROM instructor
# ALL을 삭제해도 된다.
SELECT dept_name
FROM instructor
중복이 허용된 것을 볼 수 있다.
2. 중복 제거를 강제로 수행하려면 SELECT 뒤에 DISTINCT 키워드를 삽입한다.
1) 모든 강사의 부서 이름을 찾되 중복을 제거하기:
SELECT DISTINCT dept_name
FROM instructor;
before / after
3. SELECT 절의 별표(asterisk)(*)는 "모든 속성"을 나타낸다.
SELECT * FROM instructor;4. 속성은 FROM 절 없이 리터럴(literal)일 수 있다.
(1) 결과는 한 열과 값 "437"을 가진 단일 행으로 구성된 테이블이다.
SELECT '437';(2) AS를 사용하여 열에 이름을 지정할 수 있다:
SELECT '437' AS FOO;
(3) 결과는 한 열과 N개의 행(강사 테이블의 튜플 수)으로 구성된 테이블이며, 각 행은 값 "A"를 가진다.
SELECT 'A' FROM instructor;
5. SELECT 절은 +, –, *, / 등의 연산을 포함하는 산술 표현식(arithmetic expressions)을 포함할 수 있으며, 튜플의 상수 또는 속성에 적용할 수 있다.
1) 예시
SELECT ID, name, salary/12
FROM instructor;: 이는 instructor 관계와 동일하지만, salary 속성의 값은 12로 나누어진다.

2) AS 절을 사용하여 "salary/12"의 이름을 바꿀 수 있다:
SELECT ID, name, salary/12 AS monthly_salary
FROM instructor;
WHERE 절
1. WHERE 절은 결과가 만족해야 하는(must satisfy) 조건을 지정한다.
1) 관계 대수의 선택 술어(predicate)에 해당한다(Corresponds).
2. 예: 컴퓨터 과학 부서의 모든 강사를 찾기:
SELECT name
FROM instructor
WHERE dept_name = 'Comp. Sci.';
3. SQL은 AND, OR, NOT과 같은 논리적 연결어의 사용을 허용한다.
4. 논리적 연결어의 피연산자는 <, <=, >, >=, =(EQ), <>(NEQ)와 같은 비교 연산자를 포함하는 표현식이 될 수 있다.
1) <>는 같지 않음을 의미한다( SQL에서는 !=가 없다).
5. 비교(Comparison)는 산술 표현식의 결과에 적용할 수 있다.
6. 예: 컴퓨터 과학의 모든 강사 중 급여가 70,000 이상인 강사를 찾기:
SELECT name
FROM instructor
WHERE dept_name = 'Comp. Sci.' AND salary > 70000;
7. SQL은 BETWEEN 비교 연산자를 포함한다.
8. 예: 급여가 $90,000에서 $100,000 사이인 모든 강사의 이름 찾기(즉, ≥ $90,000 및 ≤ $100,000):
SELECT name
FROM instructor
WHERE salary BETWEEN 90000 AND 100000;
9. 튜플 비교: 튜플별로 비교를 수행한다.
1) 예 : 생물학(Biology) 학과에 속하면서 강의를 담당하는 교수의 이름과 강의 ID를 검색하는 구문이다.
-> 즉, instructor.ID가 teaches.ID와 같고, instructor.dept_name이 'Biology'인 교수의 instructor.name과 해당 교수가 가르치는 teaches.course_id를 검색하는 구문이다.
- FROM절에 작성한 내용은 Courtesion product(카르테시안 곱)t와 같다. (두 개 이상의 관계에서 모든 가능한 튜플 조합을 생성하는 연산)
SELECT name, course_id
FROM instructor, teaches
WHERE (instructor.ID, dept_name) = (teaches.ID, 'Biology');
# 아래와 같이 표현도 가능하다.
WHERE instructor.ID = teaches.ID AND dept_name = 'Biology';
FROM 절
1. FROM 절은 쿼리에 포함된 관계를 나열한다.
1) 관계 대수의 데카르트 곱 연산에 해당한다.
2. 데카르트 곱 instructor × teaches 찾기:
SELECT *
FROM instructor, teaches;
1) 두 관계의 모든 속성을 가진 가능한 모든 instructor-teaches 쌍을 생성한다.
2) 공통 속성(예: ID)의 경우, 결과 테이블의 속성은 관계 이름(예: instructor.ID)을 사용하여 이름이 변경된다.
JOIN 구현
0. JOIN 종류
- NATURAL JOIN: 두 테이블에서 동일한 이름을 가진 속성을 기준으로 자동으로 JOIN을 수행하며, 중복되는 속성은 한 번만 포함된다.
- INNER JOIN: 두 테이블에서 조인 조건을 만족하는 튜플만 반환한다. (기본적인 JOIN 연산)
- LEFT JOIN: 왼쪽 테이블의 모든 튜플을 포함하고, 오른쪽 테이블에 일치하는 값이 없으면 NULL을 반환한다.
- RIGHT JOIN: 오른쪽 테이블의 모든 튜플을 포함하고, 왼쪽 테이블에 일치하는 값이 없으면 NULL을 반환한다.
- OUTER JOIN: LEFT JOIN과 RIGHT JOIN을 포함하는 개념으로, 한쪽 테이블에 없는 값이 있어도 NULL을 채워 반환한다.
- FULL JOIN: 두 테이블에서 일치하는 튜플을 포함하고, 일치하는 값이 없는 경우 NULL을 포함하여 반환한다.
1. 데카르트 곱은 직접적으로 유용하지 않지만, WHERE 절 조건(관계 대수의 선택 연산)과 결합하면 유용하다.
1) 데카르트 곱 + 선택 = 조인
2) 예: 일부 과목을 가르친 모든 강사의 이름과 course_id 찾기:
SELECT name, course_id
FROM instructor, teaches
WHERE instructor.ID = teaches.ID;3) 예 : 음악 부서의 모든 강사 중 일부 과목을 가르친 강사의 이름과 course_id 찾기:
SELECT name, course_id
FROM instructor, teaches
WHERE instructor.ID = teaches.ID AND instructor.dept_name = 'Music';이름 바꾸기 연산
1. SQL은 AS 절을 사용하여 관계와 속성의 이름을 바꾸는 것을 허용한다:
old-name AS new-name2. 'Comp. Sci.'에 있는 어떤 강사보다 급여가 높은 모든 강사의 이름 찾기:
SELECT DISTINCT T.name
FROM instructor AS T, instructor AS S
WHERE T.salary > S.salary AND S.dept_name = 'Comp. Sci.';
3. 키워드 AS는 선택 사항이며 생략할 수 있다.
instructor AS T ≡ instructor TNULL 값
1. 튜플의 일부 속성에 NULL 값이 있을 수 있다.
1) NULL은 알 수 없는 값(unknown) 또는 값이 존재하지 않음을 나타낸다.
2. NULL이 포함된 산술 표현식의 결과는 NULL이다.
1) 예: 5 + NULL은 NULL을 반환한다.
IS NULL / IS NOT NULL
1. IS NULL 술어(predicte)는 NULL 값을 확인하는 데 사용된다.
1) 예: 급여가 NULL인 모든 강사를 찾기:
SELECT name
FROM instructor
WHERE salary IS NULL;2. IS NOT NULL 술어는 적용되는 값이 NULL이 아닐 때 성공한다.
집합 연산
1. 집합 연산 UNION, INTERSECT, EXCEPT
1) 위의 각 연산은 자동으로 중복을 제거한다(eliminates duplicates).
2. 모든 중복을 유지하려면 ALL을 사용한다:
- UNION ALL (∪)
- INTERSECT ALL (∩)
- EXCEPT ALL (-)
3. 참고: SELECT는 기본적으로 모든 중복을 유지한다.
집합 연산: UNION(합집합)
1. 2017년 가을 또는 2018년 봄에 진행된 과목 찾기: (합집합)
(SELECT course_id FROM teaches WHERE semester = 'Fall' AND year = 2017)
UNION
(SELECT course_id FROM teaches WHERE semester = 'Spring' AND year = 2018);집합 연산 : INTERSECT (교집합)
1. 2017년 가을 및 2018년 봄에 진행된 과목 찾기: (교집합)
1) 코드
(SELECT course_id FROM teaches WHERE semester = 'Fall' AND year = 2017)
INTERSECT
(SELECT course_id FROM teaches WHERE semester = 'Spring' AND year = 2018);2) 참고: MySQL은 INTERSECT를 지원하지 않는다.
(1) JOIN을 사용하여 INTERSECT를 에뮬레이트할 수 있다(이후 JOIN을 학습할 예정).
(2) 코드
SELECT LT.course_id
FROM (SELECT course_id FROM teaches WHERE semester = 'Fall' AND year = 2017) AS LT
JOIN (SELECT course_id FROM teaches WHERE semester = 'Spring' AND year = 2018) AS RT
ON LT.course_id = RT.course_id;집합 연산: EXCEPT (차집합)
1. 2017년 가을에 진행된 과목 중 2018년 봄에 진행되지 않은 과목 찾기:
1) 코드
(SELECT course_id FROM teaches WHERE semester = 'Fall' AND year = 2017)
EXCEPT
(SELECT course_id FROM teaches WHERE semester = 'Spring' AND year = 2018);2) 참고: MySQL은 EXCEPT를 지원하지 않는다.
(1) NOT IN을 사용하여 EXCEPT를 에뮬레이트할 수 있다.
(2) 코드
SELECT course_id
FROM teaches
WHERE semester = 'Fall' AND year = 2017 AND course_id NOT IN
(SELECT course_id FROM teaches WHERE semester = 'Spring' AND year = 2018);(자체 정리) SImple Query vs Nested Query
Simple Query vs. Nested Query
Simple Query (단순 쿼리 2개): 독립적인 SELECT 문 두 개.
SELECT name FROM instructor; SELECT name FROM student;
Nested Query (중첩 쿼리): 내부 SELECT 결과를 외부 쿼리가 참조.
SELECT course_id FROM teaches WHERE ID IN (SELECT ID FROM instructor WHERE dept_name = 'CS');
차이점
구분Simple QueryNested Query
실행 방식 | 독립 실행 | 내부 쿼리 결과 활용 |
연산자 | UNION, INTERSECT 등 | IN, EXISTS 등 |
활용 | 개별 조회 | 조건 기반 데이터 필터링 |
문자열 연산
1. SQL은 문자 문자열 비교(comparisons)를 위한 문자열 일치 연산자를 포함한다.
2. LIKE 연산자는 두 가지 특수 문자를 사용하여 설명된 패턴을 사용한다:
- 퍼센트(%) – % 문자는 모든 하위 문자열과 일치한다
- 밑줄(_) – _ 문자는 모든 문자와 일치한다.
3. 이름에 “ri”라는 하위 문자열이 포함된 모든 강사의 이름 찾기:
SELECT name
FROM instructor
WHERE name LIKE ‘%ri%';4. 이스케이프 문자: 백슬래시(\)를 이스케이프 문자로 사용한다.
1) 예: 문자열 “100%”와 일치시키기:
LIKE '100 \%' ESCAPE ‘\’;5. 패턴은 대소문자를 구분한다(sensitive).
1) 예시:
- 'Intro%'는 “Intro”로 시작하는 모든 문자열과 일치한다.
- '%Comp%'는 “Comp”라는 하위 문자열을 포함하는 모든 문자열과 일치한다.
- '_ _ _'는 정확히 세 문자로 이루어진 모든 문자열과 일치한다.
- '_ _ _ %'는 최소 세 문자로 이루어진 모든 문자열과 일치한다.
6 SQL은 문자열 연결(“||” 사용), 대문자를 소문자로 변환(또는 그 반대), 문자열 길이 찾기, 부분 문자열 추출 등 다양한 문자열 연산을 지원한다.
튜플 표시 순서 지정
1. 모든 강사의 이름을 알파벳 순서로 나열하기
SELECT DISTINCT name
FROM instructor
ORDER BY name;
2. 여러 속성을 기준으로 정렬할 수 있다.
1) 예시
SELECT dept_name, name
FROM instructor
ORDER BY dept_name, name;
3. 각 속성에 대해 내림차순 또는 오름차순으로 DESC 또는 ASC를 지정할 수 있다; 기본값은 오름차순이다.
1) 예시
ORDER BY name DESC;
집계 함수 (Aggregate Functions)
1. 이러한 함수는 관계의 열 값 다중 집합에 대해 작동하며, 값을 반환한다.
- AVG: 평균 값
- MIN: 최소 값
- MAX: 최대 값
- SUM: 값의 합
- COUNT: 값의 수
집계 함수 예시
1. 컴퓨터 과학 부서의 강사 평균 급여 찾기:
SELECT AVG(salary)
FROM instructor
WHERE dept_name = 'Comp. Sci.';2. 2018년 봄 학기에 과목을 가르치는 강사의 총 수 찾기:
SELECT COUNT(DISTINCT ID)
FROM teaches
WHERE semester = 'Spring' AND year = 2018;3. teaches 관계의 튜플 수 찾기:
SELECT COUNT(*)
FROM teaches;집계 함수: GROUP BY
1. 각 부서의 강사 평균 급여 찾기:
SELECT dept_name, AVG(salary) AS avg_salary
FROM instructor
GROUP BY dept_name;
집계
1. SELECT 절의 속성은 집계 함수 외에 GROUP BY 목록에 나타나야 한다.
이유)- SELECT 절에 포함된 ID가 GROUP BY 목록에 포함되지 않았기 때문이다.- GROUP BY dept_name을 사용하면 dept_name별로 그룹화되지만, ID는 개별적인 값이므로 어떤 기준으로 선택할지 모호하다. - 따라서 ID를 GROUP BY에 포함하거나, 집계 함수(MIN(ID), MAX(ID) 등)를 사용해야 한다.
1) /* 잘못된 쿼리 */
SELECT dept_name, ID, AVG(salary)
FROM instructor
GROUP BY dept_name;집계 함수 – HAVING 절
1. 평균 급여가 65000을 초과하는 모든 부서의 이름과 평균 급여 찾기:
SELECT dept_name, AVG(salary) AS avg_salary
FROM instructor
GROUP BY dept_name
HAVING AVG(salary) > 65000;2. 주의: HAVING 절의 술어는 그룹 형성(formation) 후 적용되며, WHERE 절의 술어는 그룹 형성(formation) 전에 적용된다.
1) HAVING절
SELECT dept_name, AVG(salary) AS avg_salary
FROM instructor
GROUP BY dept_name
HAVING AVG(salary) > 65000;
모든 instructor 데이터를 dept_name별로 그룹화한 후, AVG(salary)가 65,000을 초과하는 그룹만 선택한다.
개별 행이 아닌 그룹 기준으로 필터링할 때 사용된다.
2) WHERE절
SELECT dept_name, AVG(salary) AS avg_salary
FROM instructor
WHERE salary > 65000
GROUP BY dept_name;
WHERE salary > 65000을 먼저 적용하여, salary가 65,000 이하인 행을 제거한 후 dept_name별로 그룹화한다.
따라서 그룹화 전 필터링이 이루어지므로, 특정 조건을 만족하는 행들만 AVG(salary) 계산에 포함된다.
SQL 명령

- retrieval of data
- manipulate data from storage
INSERT
1. 기본 구문
1) 모든 열에 데이터 삽입:
INSERT INTO tablename VALUES (col1_value, col2_value, …) (1) 테이블 스키마와 동일한 순서로 값을 나열해야 한다. -> 즉, 컬럼명을 생략하면 테이블 생성 시 정의된 컬럼 순서와 동일하게 값을 넣어야 한다는 뜻이다.
(2) 일부 데이터 값이 알 수 없을 경우 NULL 입력해야 한다.
(3) 문자 시퀀스의 경우 인용 부호(quotation marks) 사용.
- 단일 인용 부호(')가 선호되며, 이중 인용 부호(")도 허용된다.
- 인용된 값은 대소문자를 구분한다.
2) 선택된 열에 데이터 삽입: NOT NULL이 아닌 경우, 특정 컬럼을 제외하여 insert가 가능하다.
INSERT INTO tablename (col1_name, col3_name, col4_name, …)
VALUES (col1_value, col3_value, col4_value, …)2. course에 새 튜플 추가:
INSERT INTO course VALUES ('CS-437', 'Database Systems', 'Comp. Sci.', 4);3. 또는 동등하게:
INSERT INTO course (course_id, title, dept_name, credits)
VALUES ('CS-437', 'Database Systems', 'Comp. Sci.', 4);4. tot_creds가 NULL로 설정된 student에 새 튜플 추가:
INSERT INTO student VALUES ('3003', 'Green', 'Finance', null);5. 외래 키는 한 관계의 속성이 다른 관계의 튜플에 매핑되어야 함을 지정한다. -> 외래 키(Foreign Key)는 한 테이블의 속성이 다른 테이블의 특정 컬럼(기본 키 등)에 존재하는 값과 매핑되어야 한다는 제약을 의미한다.
1) 한 관계의 값은 다른 관계에 존재해야 한다.

6. 새 행이 참조하는 모든 외래 키가 데이터베이스에 이미 추가되어야 한다.
1) 참조된 관계에 해당 값이 존재하지 않는 한 외래 키 값을 삽입할 수 없다.
7. 다른 SELECT 쿼리의 결과 삽입:
1) 144학점 이상을 취득한 음악학과의 각 학생을 18,000달러의 급여를 받는 음악학과의 강사로 만든다.
INSERT INTO instructor
SELECT ID, name, dept_name, 18000
FROM student
WHERE dept_name = 'Music’ AND total_cred > 144;2) SELECT FROM WHERE 문은 결과가 관계에 삽입되기 전에 완전히 평가된다. -> SELECT FROM WHERE 문이 완전히 실행된 후에 결과가 INSERT 문으로 삽입된다
(1) 그렇지 않으면 다음과 같은 쿼리에서 문제가 발생할 수 있다:
INSERT INTO table1 SELECT * FROM table1: 이 쿼리는 table1의 기존 데이터를 읽어 다시 table1에 삽입하는 동작을 한다.문제 상황)- SELECT * FROM table1이 기존 데이터를 가져옴- 그 데이터를 INSERT INTO table1로 다시 삽입- 만약 SELECT 문이 즉시 변경된 테이블을 다시 읽는다면, 삽입된 데이터도 포함되어 무한 복사가 발생할 수 있음
UPDATE
1. 기본 구문
1) 테이블 업데이트:
# 테이블의 모든 레코드 업데이트
UPDATE tablename
SET col1_name = new_col1_value, col2_name = new_col2_value, …;2) 조건을 가진 테이블 업데이트:
UPDATE tablename
SET col1_name = new_col1_value, col2_name = new_col2_value, … WHERE predicate;2. 모든 강사에게 5% 급여 인상:
UPDATE instructor
SET salary = salary * 1.05;3. 70000 미만의 강사에게 5% 급여 인상:
UPDATE instructor
SET salary = salary * 1.05
WHERE salary < 70000;4. 평균 미만의 강사에게 5% 급여 인상:
UPDATE instructor
SET salary = salary * 1.05
WHERE salary < (SELECT AVG(salary) FROM instructor);5. 100,000 이상 강사에게 3% 급여 인상, 나머지에게 5% 인상:
1) 두 개의 UPDATE 문 작성:
UPDATE instructor SET salary = salary * 1.03 WHERE salary > 100000;UPDATE instructor SET salary = salary * 1.05 WHERE salary <= 100000;2) 순서가 중요하다.
3) CASE 문을 사용하여 더 나은 방법으로 처리 가능:
조건부 업데이트에 대한 사례 설명
1. 다음 쿼리는 이전 업데이트 쿼리와 동일하다.
UPDATE instructor
SET salary =
CASE
WHEN salary <= 100000 THEN salary * 1.05
ELSE salary * 1.03
ENDUPDATE와 스칼라 서브쿼리
1. 모든 학생의 tot_creds 값을 재계산하고 업데이트:
UPDATE student S
SET tot_cred =
(SELECT SUM(credits)
FROM takes, course
WHERE takes.course_id = course.course_id
AND S.ID = takes.ID
AND takes.grade <> 'F'
AND takes.grade IS NOT NULL);DELETE
1. 기본 구문
1) 특정 행 삭제:
DELETE FROM tablename
WHERE predicate;2) 모든 행 삭제:
DELETE FROM tablename;(1) 이는 TRUNCATE와 동일하다:
TRUNCATE (TABLE) tablename;(2) 외래 키 제약 조건이 있는 테이블은 잘라낼 수 없다. -> TRUNCATE TABLE은 모든 데이터를 즉시 삭제하는 명령인데, 만약 이 테이블이 다른 테이블의 외래 키(Foreign Key)로 참조되고 있다면 참조 무결성이 깨질 수 있기 때문이다.
- 먼저 제약 조건을 비활성화해야 한다.
- DELETE는 한 행씩 삭제하는 방식이라 가능하지만, TRUNCATE는 한 번에 삭제하는 방식이라 외래 키가 있는 경우 사용할 수 없음
ALTER TABLE tablename
DISABLE CONSTRAINT constraint_name;3) 모든 강사 삭제:
DELETE FROM instructor;4) 재무 부서의 모든 강사 삭제:
DELETE FROM instructor
WHERE dept_name = 'Finance';5) Watson 건물에 위치한 부서와 관련된 강사 튜플 삭제:
DELETE FROM instructor
WHERE dept_name IN (SELECT dept_name FROM department WHERE building = 'Watson');6) 강사의 급여가 평균 급여보다 낮은 모든 강사 삭제:
# 오류 (왜지)
DELETE FROM Instructor
WHERE salary < (SELECT AVG(salary) FROM Instructor);
# 해결
DELETE FROM Instructor
WHERE salary <= (select temp.avg FROM (SELECT AVG(salary) as avg FROM Instructor) AS temp);7) 문제: instructor에서 튜플을 삭제하면서 평균 급여가 변동된다.
(1) SQL에서 사용되는 해결 방법:
- 먼저 AVG(salary)를 계산하고 삭제할 모든 튜플을 찾는다.
- 다음으로 위에서 찾은 모든 튜플을 삭제한다 (AVG 재계산 없이).
EOF
- 다음 내용: 구조적 쿼리 언어에 대한 추가 내용.