0030

학교

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 쿼리는 다음과 같은 형식을 가진다:

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. 예시: 모든 강사의 이름 찾기

SQL
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 키워드는 중복이 제거되지 않아야 함을 지정한다.

SQL
SELECT ALL dept_name 
FROM instructor

# ALL을 삭제해도 된다.
SELECT dept_name
FROM instructor

중복이 허용된 것을 볼 수 있다.

2. 중복 제거를 강제로 수행하려면 SELECT 뒤에 DISTINCT 키워드를 삽입한다.

1) 모든 강사의 부서 이름을 찾되 중복을 제거하기:

SQL
SELECT DISTINCT dept_name 
FROM instructor;

before / after

3. SELECT 절의 별표(asterisk)(*)는 "모든 속성"을 나타낸다.

SQL
SELECT * FROM instructor;

4. 속성은 FROM 절 없이 리터럴(literal)일 수 있다.

(1) 결과는 한 열과 값 "437"을 가진 단일 행으로 구성된 테이블이다.

SQL
SELECT '437';

(2) AS를 사용하여 열에 이름을 지정할 수 있다:

SQL
SELECT '437' AS FOO;

(3) 결과는 한 열과 N개의 행(강사 테이블의 튜플 수)으로 구성된 테이블이며, 각 행은 값 "A"를 가진다.

SQL
SELECT 'A' FROM instructor;

5. SELECT 절은 +, –, *, / 등의 연산을 포함하는 산술 표현식(arithmetic expressions)을 포함할 수 있으며, 튜플의 상수 또는 속성에 적용할 수 있다.

1) 예시

SQL
SELECT ID, name, salary/12 
FROM instructor;

: 이는 instructor 관계와 동일하지만, salary 속성의 값은 12로 나누어진다.

2) AS 절을 사용하여 "salary/12"의 이름을 바꿀 수 있다:

SQL
SELECT ID, name, salary/12 AS monthly_salary 
FROM instructor;

WHERE 절

1. WHERE 절은 결과가 만족해야 하는(must satisfy) 조건을 지정한다.

1) 관계 대수의 선택 술어(predicate)에 해당한다(Corresponds).

2. 예: 컴퓨터 과학 부서의 모든 강사를 찾기:

SQL
SELECT name 
FROM instructor 
WHERE dept_name = 'Comp. Sci.';

3. SQL은 AND, OR, NOT과 같은 논리적 연결어의 사용을 허용한다.

4. 논리적 연결어의 피연산자는 <, <=, >, >=, =(EQ), <>(NEQ)와 같은 비교 연산자를 포함하는 표현식이 될 수 있다.

1) <>는 같지 않음을 의미한다( SQL에서는 !=가 없다).

5. 비교(Comparison)는 산술 표현식의 결과에 적용할 수 있다.

6. 예: 컴퓨터 과학의 모든 강사 중 급여가 70,000 이상인 강사를 찾기:

SQL
SELECT name 
FROM instructor
WHERE dept_name = 'Comp. Sci.' AND salary > 70000;

7. SQL은 BETWEEN 비교 연산자를 포함한다.

8. 예: 급여가 $90,000에서 $100,000 사이인 모든 강사의 이름 찾기(즉, ≥ $90,000 및 ≤ $100,000):

SQL
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와 같다. (두 개 이상의 관계에서 모든 가능한 튜플 조합을 생성하는 연산)

SQL
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 찾기:

SQL
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 찾기:

SQL
SELECT name, course_id 
FROM instructor, teaches 
WHERE instructor.ID = teaches.ID;

3) 예 : 음악 부서의 모든 강사 중 일부 과목을 가르친 강사의 이름과 course_id 찾기:

SQL
SELECT name, course_id 
FROM instructor, teaches 
WHERE instructor.ID = teaches.ID AND instructor.dept_name = 'Music';

이름 바꾸기 연산

1. SQL은 AS 절을 사용하여 관계와 속성의 이름을 바꾸는 것을 허용한다:

SQL
old-name AS new-name

2. 'Comp. Sci.'에 있는 어떤 강사보다 급여가 높은 모든 강사의 이름 찾기:

SQL
SELECT DISTINCT T.name 
FROM instructor AS T, instructor AS S 
WHERE T.salary > S.salary AND S.dept_name = 'Comp. Sci.';

3. 키워드 AS는 선택 사항이며 생략할 수 있다.

SQL
instructor AS T ≡ instructor T

NULL 값

1. 튜플의 일부 속성에 NULL 값이 있을 수 있다.

1) NULL은 알 수 없는 값(unknown) 또는 값이 존재하지 않음을 나타낸다.

2. NULL이 포함된 산술 표현식의 결과는 NULL이다.

1) 예: 5 + NULL은 NULL을 반환한다.

IS NULL / IS NOT NULL

1. IS NULL 술어(predicte)는 NULL 값을 확인하는 데 사용된다.

1) 예: 급여가 NULL인 모든 강사를 찾기:

SQL
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년 봄에 진행된 과목 찾기: (합집합)

SQL
(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) 코드

SQL
(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) 코드

SQL
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) 코드

SQL
(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) 코드

SQL
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”라는 하위 문자열이 포함된 모든 강사의 이름 찾기:

SQL
SELECT name 
FROM instructor 
WHERE name LIKE ‘%ri%';

4. 이스케이프 문자: 백슬래시(\)를 이스케이프 문자로 사용한다.

1) 예: 문자열 “100%”와 일치시키기:

SQL
LIKE '100 \%' ESCAPE ‘\’;

5. 패턴은 대소문자를 구분한다(sensitive).

1) 예시:

- 'Intro%'는 “Intro”로 시작하는 모든 문자열과 일치한다.

- '%Comp%'는 “Comp”라는 하위 문자열을 포함하는 모든 문자열과 일치한다.

- '_ _ _'는 정확히 세 문자로 이루어진 모든 문자열과 일치한다.

- '_ _ _ %'는 최소 세 문자로 이루어진 모든 문자열과 일치한다.

6 SQL은 문자열 연결(“||” 사용), 대문자를 소문자로 변환(또는 그 반대), 문자열 길이 찾기, 부분 문자열 추출 등 다양한 문자열 연산을 지원한다.

튜플 표시 순서 지정

1. 모든 강사의 이름을 알파벳 순서로 나열하기

SQL
SELECT DISTINCT name 
FROM instructor 
ORDER BY name;

2. 여러 속성을 기준으로 정렬할 수 있다.

1) 예시

SQL
SELECT dept_name, name 
FROM instructor 
ORDER BY dept_name, name;

3. 각 속성에 대해 내림차순 또는 오름차순으로 DESC 또는 ASC를 지정할 수 있다; 기본값은 오름차순이다.

1) 예시

SQL
ORDER BY name DESC;

집계 함수 (Aggregate Functions)

1. 이러한 함수는 관계의 열 값 다중 집합에 대해 작동하며, 값을 반환한다.

- AVG: 평균 값

- MIN: 최소 값

- MAX: 최대 값

- SUM: 값의 합

- COUNT: 값의 수

집계 함수 예시

1. 컴퓨터 과학 부서의 강사 평균 급여 찾기:

SQL
SELECT AVG(salary) 
FROM instructor 
WHERE dept_name = 'Comp. Sci.';

2. 2018년 봄 학기에 과목을 가르치는 강사의 총 수 찾기:

SQL
SELECT COUNT(DISTINCT ID) 
FROM teaches 
WHERE semester = 'Spring' AND year = 2018;

3. teaches 관계의 튜플 수 찾기:

SQL
SELECT COUNT(*) 
FROM teaches;

집계 함수: GROUP BY

1. 각 부서의 강사 평균 급여 찾기:

SQL
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) /* 잘못된 쿼리 */

SQL
SELECT dept_name, ID, AVG(salary) 
FROM instructor 
GROUP BY dept_name;

집계 함수 – HAVING 절

1. 평균 급여가 65000을 초과하는 모든 부서의 이름과 평균 급여 찾기:

SQL
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절

SQL
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절

SQL
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) 모든 열에 데이터 삽입:

SQL
INSERT INTO tablename VALUES (col1_value, col2_value, …)

(1) 테이블 스키마와 동일한 순서로 값을 나열해야 한다. -> 즉, 컬럼명을 생략하면 테이블 생성 시 정의된 컬럼 순서와 동일하게 값을 넣어야 한다는 뜻이다.

(2) 일부 데이터 값이 알 수 없을 경우 NULL 입력해야 한다.

(3) 문자 시퀀스의 경우 인용 부호(quotation marks) 사용.

- 단일 인용 부호(')가 선호되며, 이중 인용 부호(")도 허용된다.

- 인용된 값은 대소문자를 구분한다.

2) 선택된 열에 데이터 삽입: NOT NULL이 아닌 경우, 특정 컬럼을 제외하여 insert가 가능하다.

SQL
INSERT INTO tablename (col1_name, col3_name, col4_name, …) 
VALUES (col1_value, col3_value, col4_value, …)

2. course에 새 튜플 추가:

SQL
INSERT INTO course VALUES ('CS-437', 'Database Systems', 'Comp. Sci.', 4);

3. 또는 동등하게:

SQL
INSERT INTO course (course_id, title, dept_name, credits) 
VALUES ('CS-437', 'Database Systems', 'Comp. Sci.', 4);

4. tot_creds가 NULL로 설정된 student에 새 튜플 추가:

SQL
INSERT INTO student VALUES ('3003', 'Green', 'Finance', null);

5. 외래 키는 한 관계의 속성이 다른 관계의 튜플에 매핑되어야 함을 지정한다. -> 외래 키(Foreign Key)는 한 테이블의 속성이 다른 테이블의 특정 컬럼(기본 키 등)에 존재하는 값과 매핑되어야 한다는 제약을 의미한다.

1) 한 관계의 값은 다른 관계에 존재해야 한다.

6. 새 행이 참조하는 모든 외래 키가 데이터베이스에 이미 추가되어야 한다.

1) 참조된 관계에 해당 값이 존재하지 않는 한 외래 키 값을 삽입할 수 없다.

7. 다른 SELECT 쿼리의 결과 삽입:

1) 144학점 이상을 취득한 음악학과의 각 학생을 18,000달러의 급여를 받는 음악학과의 강사로 만든다.

SQL
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) 그렇지 않으면 다음과 같은 쿼리에서 문제가 발생할 수 있다:

SQL
INSERT INTO table1 SELECT * FROM table1

: 이 쿼리는 table1의 기존 데이터를 읽어 다시 table1에 삽입하는 동작을 한다.문제 상황)- SELECT * FROM table1이 기존 데이터를 가져옴- 그 데이터를 INSERT INTO table1로 다시 삽입- 만약 SELECT 문이 즉시 변경된 테이블을 다시 읽는다면, 삽입된 데이터도 포함되어 무한 복사가 발생할 수 있음

UPDATE

1. 기본 구문

1) 테이블 업데이트:

SQL
# 테이블의 모든 레코드 업데이트
UPDATE tablename 
SET col1_name = new_col1_value, col2_name = new_col2_value, …;

2) 조건을 가진 테이블 업데이트:

SQL
UPDATE tablename 
SET col1_name = new_col1_value, col2_name = new_col2_value, … WHERE predicate;

2. 모든 강사에게 5% 급여 인상:

SQL
UPDATE instructor 
SET salary = salary * 1.05;

3. 70000 미만의 강사에게 5% 급여 인상:

SQL
UPDATE instructor 
SET salary = salary * 1.05 
WHERE salary < 70000;

4. 평균 미만의 강사에게 5% 급여 인상:

SQL
UPDATE instructor 
SET salary = salary * 1.05 
WHERE salary < (SELECT AVG(salary) FROM instructor);

5. 100,000 이상 강사에게 3% 급여 인상, 나머지에게 5% 인상:

1) 두 개의 UPDATE 문 작성:

SQL
UPDATE instructor SET salary = salary * 1.03 WHERE salary > 100000;
SQL
UPDATE instructor SET salary = salary * 1.05 WHERE salary <= 100000;

2) 순서가 중요하다.

3) CASE 문을 사용하여 더 나은 방법으로 처리 가능:

조건부 업데이트에 대한 사례 설명

1. 다음 쿼리는 이전 업데이트 쿼리와 동일하다.

SQL
UPDATE instructor 
SET salary = 
   CASE
     WHEN salary <= 100000 THEN salary * 1.05 
     ELSE salary * 1.03 
   END

UPDATE와 스칼라 서브쿼리

1. 모든 학생의 tot_creds 값을 재계산하고 업데이트:

SQL
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) 특정 행 삭제:

SQL
DELETE FROM tablename 
WHERE predicate;

2) 모든 행 삭제:

SQL
DELETE FROM tablename;

(1) 이는 TRUNCATE와 동일하다:

SQL
TRUNCATE (TABLE) tablename;

(2) 외래 키 제약 조건이 있는 테이블은 잘라낼 수 없다. -> TRUNCATE TABLE 모든 데이터를 즉시 삭제하는 명령인데, 만약 이 테이블이 다른 테이블의 외래 키(Foreign Key)로 참조되고 있다면 참조 무결성이 깨질 수 있기 때문이다.

- 먼저 제약 조건을 비활성화해야 한다.

- DELETE는 한 행씩 삭제하는 방식이라 가능하지만, TRUNCATE는 한 번에 삭제하는 방식이라 외래 키가 있는 경우 사용할 수 없음

SQL
ALTER TABLE tablename 
DISABLE CONSTRAINT constraint_name;

3) 모든 강사 삭제:

SQL
DELETE FROM instructor;

4) 재무 부서의 모든 강사 삭제:

SQL
DELETE FROM instructor 
WHERE dept_name = 'Finance';

5) Watson 건물에 위치한 부서와 관련된 강사 튜플 삭제:

SQL
DELETE FROM instructor 
WHERE dept_name IN (SELECT dept_name FROM department WHERE building = 'Watson');

6) 강사의 급여가 평균 급여보다 낮은 모든 강사 삭제:

SQL
# 오류 (왜지)
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

- 다음 내용: 구조적 쿼리 언어에 대한 추가 내용.