데이터베이스/데이터베이스 언어 SQL (5)
2024-06-06 23:24:56

삽입 SQL의 개념과 특징

 지금까지 살펴본 SQL 문은 DBMS에 대화식으로 직접 입력하여 수행 결과를 바로 확인할 수 있지만, 응용 프로그램 안에 삽입해 사용할 수도 있다. C, C++, JAVA 등과 같은 프로그래밍 언어로 작성된 응용 프로그램 안에 삽입하여 사용하는 SQL 문을 삽입 SQL 이라 한다.

 

 일반 SQL 문과 달리 응용 프로그램에 삽입 SQL 문을 사용할 때는 다음과 같은 특징을 염두에 두어야 한다.

 

1. 삽입 SQL 문은 프로그램 안에서 일반 명령문이 위치할 수 있는 곳이면 어디든 삽입할 수 있다.

 

2. 프로그램 안의 일반 명령문과 구별하기 위해 삽입 SQL 문 앞에 EXEC SQL을 붙인다.

 

3. 프로그램에 선언된 일반 변수를 삽입 SQL 문에서 사용할 수 있다. 단, SQL 문에서 일반 변수를 사용할 때는 앞에 콜론(:)을 붙여 테이블 이름이나 속성의 이름과 구분한다.

 

 수행 결과로 여러 개의 행을 반환하는 SELECT 문을 삽입 SQL 문으로 사용하는 경우에는 커서(cursor)라는 도구가 필요하다. 커서는 수행 결과로 반환된 여러 행을 한 번에 하나씩 가리키는 포인터 역할을 한다. 프로그램에서는 SELECT 문의 수행 결과로 반환되는 여러 행을 한꺼번에 처리할 수 없으므로 커서를 이용해 한 번에 한 행씩 차례로 처리해야 한다.

 

 이 책에서는 커서가 필요 없는 삽입 SQL과 커서가 필요한 삽입 SQL 을 C 언어로 작성한 프로그램을 예로 들어 설명했다. 하지만 필자는 Python 언어를 주 언어로 사용하기 때문에 Python 프로그램에서 앞서 학습한 데이터를 출력하는 코드를 작성했다.

#라이브러리 선언
import pymysql

#데이터베이스 연결
conn = pymysql.connect(host = 'localhost', user = 'root', password = '패스워드_입력', db = 'DB_이름_입력', charset = 'utf8')

#커서 생성
curs = conn.cursor()

#SQL 문 실행
sql = 'select * from 테이블_이름'
curs.execute(sql)

#데이터 가져오기
data = curs.fetchall()
data[0]
data[1]

#연결 끊기
conn.close()

 

 학습에 사용한 테이블의 개수는 총 3개로 각각 고객, 제품, 주문 테이블이다. 따라서 각각의 테이블을 가리키는 커서가 3개 필요하다. 추가로 데이터를 행렬로 표현하기 위해 pandas 라이브러리를 사용하여 코드를 다시 작성해보았다.

#라이브러리 선언
import pymysql
import pandas as pd

#데이터베이스 연결
conn = pymysql.connect(host = 'localhost', user = 'root', password = '패스워드_입력', db = 'DB_이름_입력', charset = 'utf8')

#커서 생성
curs1 = conn.cursor()
curs2 = conn.cursor()
curs3 = conn.cursor()

#SQL 문 실행
sql1 = 'select * from 고객'
sql2 = 'select * from 제품'
sql3 = 'select * from 주문'
curs1.execute(sql1)
curs2.execute(sql2)
curs3.execute(sql3)

#데이터 가져오기
data1 = curs1.fetchall()
data2 = curs2.fetchall()
data3 = curs3.fetchall()

#고객 테이블 출력
df1 = pd.DataFrame(data1)
lables1 = ['고객아이디', '고객이름', '나이', '등급', '직업', '적립금']
df1.columns = lables1
df1

#제품 테이블 출력
df2 = pd.DataFrame(data2)
lables2 = ['제품번호', '제품명', '재고량', '단가', '제조업체']
df2.columns = lables2
df2

#주문 테이블 출력
df3 = pd.DataFrame(data3)
lables3 = ['주문번호', '주문고객', '주문제품', '수량', '배송지', '주문일자']
df3.columns = lables3
df3

 

 

고객 테이블 출력

 

제품 테이블 출력

 

주문 테이블 출력

 

'데이터베이스 > 데이터베이스 언어 SQL' 카테고리의 다른 글

  (0) 2024.06.06
SQL을 이용한 데이터 조작  (0) 2024.06.02
SQL을 이용한 데이터 정의  (0) 2024.06.01
SQL의 소개  (0) 2024.06.01
2024-06-06 13:45:21

뷰의 개념

 뷰는 다른 테이블을 기반으로 만들어진 가상 테이블(virtual table)이다. 이렇게 부르는 이유는 일반 테이블과 달리 데이터를 실제로 저장하지 않기 때문이다.

 

 뷰를 만드는 데 기반이 되는 물리적인 테이블을 기본 테이블이라고 하는데 CREATE TABLE 문으로 정의한 테이블이 기본 테이블로 사용된다. 일반적으로 뷰는 기본 테이블을 기반으로 만들어지지만 다른 뷰를 기반으로 새로운 뷰를 만들 수도 있다.

 

 뷰를 통해 기본 테이블의 내용을 쉽게 검색할 수는 있지만 기본 테이블의 내용을 바꾸는 작업은 제한적으로 이루어진다.

 

뷰의 생성

#기본코드
CREATE VIEW 뷰_이름[(속성_리스트)] AS SELECT 문 [WITH CHECK OPTION];

 

예제 55

 고객 테이블에서 등급이 vip 인 고객의 고객아이디, 고객이름, 나이로 구성된 뷰를 우수고객이라는 이름으로 생성해보자. 그런 다음 우수고객 뷰의 모든 내용을 검색해보자.

#작성코드 / 정답코드와 동일
CREATE VIEW 우수고객(고객아이디, 고객이름, 나이) AS SELECT 고객아이디, 고객이름, 나이 FROM 고객 WHERE 등급 = 'vip' WITH CHECK OPTION;
SELECT * FROM 우수고객;

 

 뷰를 구성하는 속성의 이름과 기본 테이블에서 검색한 속성의 이름이 같으면 뷰를 구성하는 속성의 이름 리스트를 생략해도 된다.

 

 

예제 56

 제품 테이블에서 제조업체별 제품수로 구성된 뷰를 업체별제품수라는 이름으로 생성해보자. 그런 다음 업체별제품수 뷰의 모든 내용을 검색해보자.

#작성코드
CREATE 업체별제품수 AS SELECT 제조업체, COUNT(*) FROM 제품 GROUP BY 제조업체;
SELECT * FROM 업체별제품수;
#정답코드
CREATE VIEW 업체별제품수(제조업체, 제품수) AS SELECT 제조업체, COUNT(*) FROM 제품 GROUP BY 제조업체;
SELECT * FROM 업체별제품수;

 

 뷰를 구성하는 속성의 이름과 기본 테이블에서 검색한 속성의 이름이 다르므로 뷰를 구성하는 속성의 이름 리스트를 생략하면 안 된다.

 

 

예제 57

 우수고객 뷰에서 나이가 25세 이상인 고객에 대한 모든 내용을 검색해보자.

#작성코드 / 정답코드와 동일
SELECT * FROM 우수고객 WHERE 나이 >= 25;

 

 

 뷰가 데이터를 실제로 저장하고 있지 않는 가상 테이블이지만 SELECT 문을 이용해 데이터를 검색할 수 있다. 그 이유는 뷰에 대한 SELECT 문이 내부적으로는 기본 테이블에 대한 SELECT 문으로 변환되어 수행되기 때문이다.

 

 INSERT 문, UPDATE 문, DELETE 문도 뷰를 대상으로 수행할 수 있다. 그러나 삽입, 수정, 삭제 연산이 모든 뷰에 허용되는 것은 아니다. 뷰는 기본 테이블을 들여다 보는 창의 역할을 하기 때문에 뷰를 통한 기본 테이블의 변화는 제한적이다.

 

#예시1
CREATE VIEW 제품1 AS SELECT 제품번호, 재고량, 제조업체 FROM 제품 WITH CHECK OPTION;
SELECT * FROM 제품1;
#예시2
CREATE VIEW 제품2 AS SELECT 제품명, 재고량, 제조업체 FROM 제품 WITH CHECK OPTION;
SELECT * FROM 제품2;

 

예제58

 제품번호가 p08, 재고량이 1,000, 제조업체가 신선식품인 새로운 제품의 정보를 제품1 뷰에 삽입해보자. 그런 다음 제품1 뷰에 있는 모든 내용을 검색해보자.

#작성코드 / 정답코드와 동일
INSERT INTO 제품1(제품번호, 재고량, 제조업체) VALUES ('p08', 1000, '신선식품');
SELECT * FROM 제품1;
SELECT * FROM 제품;

 

 제품1 뷰에 있는 모든 내용을 검색하면 p08 제품에 대한 새로운 튜플이 삽입된 것을 확인할 수 있다. 또한 기본 테이블에도 같은 튜플이 삽입됐음을 알 수 있다. 뷰를 통해 값을 제시하지 않은 제품명 속성과 단가 속성에는 널 값이 저장된다.

 

#에러발생
INSERT INTO 제품2(제품명, 재고량, 제조업체) VALUES ('시원냉면', 1000, '신선식품);

 

 위 코드를 실행하면 에러가 발생한다. 그 이유는 제품 테이블의 키 값인 제품번호 속성은 NULL 값을 가질 수 없기 때문이다. UPDATE 문과 DELETE 문도 마찬가지다. 기본 테이블의 기본키 속성을 포함하고 있는 뷰는 수정과 삭제 연산이 모두 실행되지만, 기본키 속성을 포함하지 않는 뷰는 실행되지 않는다.

 

 변경이 불가능한 뷰의 중요한 특징 몇 가지를 살펴보면 다음과 같다.

 

1. 기본 테이블의 기본키를 구성하는 속성이 포함되어 있지 않은 뷰는 변경할 수 없다.

 

2. 기본 테이블에 있던 내용이 아니라 집계 함수로 새로 계산된 내용을 포함하고 있는 뷰는 변경할 수 없다.

 

3. DISTINCT 키워드를 포함하여 정의한 뷰는 변경할 수 없다.

 

4. GROUP BY 절을 포함하여 정의한 뷰는 변경할 수 없다.

 

5. 여러 개의 테이블을 조인하여 정의한 뷰는 변경할 수 없는 경우가 많다.

 

 사용함에 있어 많은 제한을 가지고 있는 뷰의 장점은 다음과 같다.

 

1. 질의문을 좀 더 쉽게 작성할 수 있다.

-> 특정 조건을 만족하는 튜플들로 뷰를 미리 만들어놓으면, 사용자가 WHERE 절 없이 뷰를 검색해도 특정 조건을 만족하는 데이터를 검색할 수 있다. 또한 GROUP BY, 집계 함수, 조인 등을 이용해 미리 뷰를 만들어놓으면, 복잡한 SQL 문을 작성하지 않아도 SELECT 절과 FROM 절만으로 원하는 데이터를 검색할 수 있다.

 

2. 데이터의 보안 유지에 도움이 된다.

-> 여러 사용자의 요구에 맞는 다양한 뷰를 미리 정의해두고 사용자가 자신에게 제공된 뷰를 통해서만 데이터에 접근하도록 권한을 설정하면, 뷰에 포함되지 않은 데이터를 사용자로부터 보호할 수 있다.

 

3. 데이터를 좀 더 편리하게 관리할 수 있다.

-> 제공된 뷰에 포함되지 않은 기본 테이블의 다른 부분은 사용자가 신경 쓸 필요가 없다. 또한 제공된 뷰와 관련이 없는 다른 테이블의 변화에도 영향을 받지 않는다.

 

뷰의 삭제

#기본코드
DROP VIEW 뷰_이름;

 

예제59

우수고객 뷰를 삭제해보자.

#작성코드 / 정답코드와 동일
DROP VIEW 우수고객;

'데이터베이스 > 데이터베이스 언어 SQL' 카테고리의 다른 글

삽입 SQL  (0) 2024.06.06
SQL을 이용한 데이터 조작  (0) 2024.06.02
SQL을 이용한 데이터 정의  (0) 2024.06.01
SQL의 소개  (0) 2024.06.01
2024-06-02 13:14:18

SQL의 데이터 조작 기능

 SQL의 데이터 조작 기능은 원하는 데이터 검색, 새로운 데이터 삽입, 데이터 수정, 데이터 삭제로 분류할 수 있다. 이 네가지 데이터 조작 기능을 위한 SQL 문의 작성 규칙을 차례로 알아보자.

 

SQL의 데이터 조작 기능

 

 

데이터의 검색

 SELECT 문은 다양한 검색 유형을 지원한다. 이 절에서는 고객, 제품, 주문 테이블로 이루어진 판매 DB를 기준으로 예제를 진행한다.

 

※ INSERT 문을 이용해 앞에서 생성한 각 테이블에 튜플을 삽입한 후 예제를 실행하는 것이 좋다.

#고객 테이블 데이터 삽입
INSERT INTO 고객 VALUES ('apple', '정소화', 20, 'gold', '학생', 1000);
INSERT INTO 고객 VALUES ('banana', '김선우', 25, 'vip', '간호사', 2500);
INSERT INTO 고객 VALUES ('carrot', '고명석', 28, 'gold', '교사', 4500);
INSERT INTO 고객 VALUES ('orange', '김용욱', 22, 'silver', '학생', 0);
INSERT INTO 고객 VALUES ('melon', '성원용', 35, 'gold', '회사원', 5000);
INSERT INTO 고객 VALUES ('peach', '오형준', NULL, 'silver', '의사', 300);
INSERT INTO 고객 VALUES ('pear', '채광주', 31, 'silver', '회사원', 500);

#제품 테이블 데이터 삽입
INSERT INTO 제품 VALUES ('p01', '그냥만두', 5000, 4500, '대한식품');
INSERT INTO 제품 VALUES ('p02', '매운쫄면', 2500, 5500, '민국푸드');
INSERT INTO 제품 VALUES ('p03', '쿵떡파이', 3600, 2600, '한빛제과');
INSERT INTO 제품 VALUES ('p04', '맛난초콜릿', 1250, 2500, '한빛제과');
INSERT INTO 제품 VALUES ('p05', '얼큰라면', 2200, 1200, '대한식품');
INSERT INTO 제품 VALUES ('p06', '통통우동', 1000, 1550, '민국푸드');
INSERT INTO 제품 VALUES ('p07', '달콤비스킷', 1650, 1500, '한빛제과');

#주문 테이블 데이터 삽입
INSERT INTO 주문 VALUES ('o01', 'apple', 'p03', 10, '서울시 마포구', '2019-01-01');
INSERT INTO 주문 VALUES ('o02', 'melon', 'p01', 5, '인천시 계양구', '2019-01-10');
INSERT INTO 주문 VALUES ('o03', 'banana', 'p06', 45, '경기도 부천시', '2019-01-11');
INSERT INTO 주문 VALUES ('o04', 'carrot', 'p02', 8, '부산시 금정구', '2019-02-01');
INSERT INTO 주문 VALUES ('o05', 'melon', 'p06', 36, '경기도 용인시', '2019-02-20');
INSERT INTO 주문 VALUES ('o06', 'banana', 'p01', 19, '충청북도 보은군', '2019-03-02');
INSERT INTO 주문 VALUES ('o07', 'apple', 'p03', 22, '서울시 영등포구', '2019-03-15');
INSERT INTO 주문 VALUES ('o08', 'pear', 'p02', 50, '강원도 춘천시', '2019-04-10');
INSERT INTO 주문 VALUES ('o09', 'banana', 'p04', 15, '전라남도 목포시', '2019-04-11');
INSERT INTO 주문 VALUES ('o10', 'carrot', 'p03', 20, '경기도 안양시', '2019-05-22');

 

기본 검색

 기본 검색을 위한 SELECT 문의 기본 형식은 다음과 같다.

SELECT 속성1, 속성2, ..., 속성n FROM 테이블_이름 ;

 

예제 10

 고객 테이블에서 고객아이디, 고객이름, 등급 속성을 검색해보자.

#작성코드 / 정답코드와 동일
SELECT 고객아이디, 고객이름, 등급 FROM 고객 ;

 

 

예제 11 == 예제 12

 고객 테이블에 존재하는 모든 속성을 검색해보자.

#작성코드
SELECT * FROM 고객 ;
#정답코드
SELECT 고객아이디, 고객이름, 나이, 등급, 직업, 적립금 FROM 고객 ;

 

 테이블에 존재하는 모든 속성을 검색하기 위해 속성의 이름을 전부 나열하지 않고 *를 사용할 수도 있다.

 

 

예제 13 == 예제 14

 제품 테이블에서 제조업체를 검색해보자.

#작성코드 / 정답코드와 동일
SELECT 제조업체 FROM 제품;

 

 관계 데이터 모델의 일반 릴레이션은 튜플의 집합 개념으로 이해할 수 있으며 튜플의 유일성을 만족해야 하기 때문에 릴레이션 하나에 동일한 튜플이 중복되면 안 된다. 그러나 SELECT 문의 수행 결과로 반환되는 결과 테이블에서는 동일한 튜플이 중복될 수 있다.

 

 결과 테이블이 중복을 허용하도록 ALL 키워드를 명시적으로 사용해도 된다. SELECT ALL 제조업체 FROM 제품;

 

 

예제 15

 제품 테이블에서 제조업체 속성을 중복 없이 검색해보자.

#작성코드 / 정답코드와 일치
SELECT DISTINCT 제조업체 FROM 제품;

 

 

 결과 테이블에 출력되는 속성의 이름을 다른 이름으로 바꾸어 출력할 수도 있다. AS 키워드를 변경할 이름과 함께 지정하면 된다. 원래 테이블의 속성 이름이 실제로 바뀌는 것은 아니다. 그리고 AS 키워드는 생략할 수 있다.

 

예제 16

 제품 테이블에서 제품명과 단가를 검색하되, 단가를 가격이라는 새 이름으로 출력해보자.

#작성코드
SELECT 제품명, AS 단가 FROM 제품;
#정답코드
SELECT 제품명, 단가 AS 가격 FROM 제품;

 

 

산술식을 이용한 검색

 SELECT 키워드와 함께 산술식을 제시할 수 있다. 산술식은 속성의 이름과 +, -, *, / 등의 산술 연산자, 상수로 구성한다.

 

예제 17

 제품 테이블에서 제품명과 단가 속성을 검색하되, 단가에 500원을 더해 '조정 단가'라는 새 이름으로 출력해보자.

#작성코드 / 정답코드와 동일
SELECT 제품명, 단가+500 AS '조정 단가' FROM 제품;

 

 변경할 이름에 띄어쓰기가 들어가는 경우, 따옴표를 사용한다. 제품 테이블에 있는 단가 속성의 값이 실제로 변경되는 것은 아니다. 결과 테이블에서만 계산한 결과 값을 출력한다.

 

조건 탐색

 조건을 만족하는 데이터만 검색하는 SELECT 문의 기본 형식은 다음과 같다.

SELECT 속성1, 속성2, ..., 속성n FROM 테이블_이름 WHERE 조건;

 

예제 18

 제품 테이블에서 한빛제과가 제조한 제품의 제품명, 재고량, 단가를 검색해보자.

#작성코드
SELECT 제품명, 재고량, 단가 FROM 제품 WHERE '한빛제과';
#정답코드
SELECT 제품명, 재고량, 단가 FROM 제품 WHERE 제조업체 = '한빛제과';

 

 

예제 19

 주문 테이블에서 apple 고객이 15개 이상 주문한 주문제품, 수량, 주문일자를 검색해보자.

#작성코드 / 정답코드와 동일
SELECT 주문제품, 수량, 주문일자 FROM 주문 WHERE 주문고객 = 'apple' AND 수량 >= 15;

 

 

예제 20

 주문 테이블에서 apple 고객이 주문했거나 15개 이상 주문된 제품의 주문제품, 수량, 주문일자, 주문고객을 검색해보자.

#작성코드 / 정답코드와 동일
SELECT 주문제품, 수량, 주문일자, 주문고객 FROM 주문 WHERE 주문고객 = 'apple' OR 수량 >= 15;

 

 

예제 21

 제품 테이블에서 단가가 2,000원 이상이면서 3,000원 이하인 제품의 제품명, 단가, 제조업체를 검색해보자.

#작성코드 / 정답코드와 동일
SELECT 제품명, 단가, 제조업체 FROM 제품 WHERE 단가 >= 2000 AND 단가 <= 3000;

 

 

 

LIKE를 이용한 검색

 검색 조건을 부분적으로만 알고 있다면 LIKE 키워드를 이용해 검색할 수 있다. 검색 조건을 정확히 알면 = 연산자로 조건을 표현하면 되지만 부분적으로만 알고 있다면 = 대신 LIKE 키워드를 사용한다. 단 LIKE 키워드는 문자열을 이용하는 조건에만 사용할 수 있다.

 

LIKE 키워드와 함께 사용할 수 있는 기호

 

 

LIKE 키워드의 사용 예

 

 

예제 22

 고객 테이블에서 성이 김 씨인 고객의 고객이름, 나이, 등급, 적립금을 검색해보자.

#작성코드 / 정답코드와 동일
SELECT 고객이름, 나이, 등급, 적립금 FROM 고객 WHERE 고객이름 LIKE '김%';

 

 

예제 23

 고객 테이블에서 고객아이디가 5자인 고객의 고객아이디, 고객이름, 등급을 검색해보자.

#작성코드 / 정답코드와 동일
SELECT 고객아이디, 고객이름, 등급 FROM 고객 WHERE 고객아이디 LIKE '_____';

 

 

NULL을 이용한 검색

 검색 조건에서 특정 속성의 값이 널 값인지를 비교하려면 IS NULL 키워드를 사용한다. 반대로 특정 속성의 값이 널 값이 아닌지를 비교하려면 IS NOT NULL 키워드를 사용한다.

 

예제 24

 고객 테이블에서 나이가 아직 입력되지 않은 고객의 고객이름을 검색해보자.

#작성코드 / 정답코드와 동일
SELECT 고객이름 FROM 고객 WHERE 나이 IS NULL;

 

 

예제 25

 고객 테이블에서 나이가 이미 입력된 고객의 고객이름을 검색해보자.

#작성코드 / 정답코드와 동일
SELECT 고객이름 FROM 고객 WHERE 나이 IS NOT NULL;

 

 

정렬 검색

 SELECT 문의 검색 결과 테이블은 일반적으로 DBMS가 정한 순서로 출력된다. 결과 테이블의 내용을 사용자가 원하는 순서로 출력하려면 ORDER BY 키워드를 사용한다.

SELECT 속성1, 속성2, ..., 속성n FROM 테이블_이름 WHERE 조건 ORDER BY 속성 ASC or DESC;

 

 ORDER BY 키워드와 함께 정렬 기준이 되는 속성을 지정하고, 오름차순 정렬이면 ASC, 내림차순 정렬이면 DESC로 표현한다. 특별히 지정하지 않으면 오름차순으로 기본 정렬한다.

 

예제 26

 고객 테이블에서 고객이름, 등급, 나이를 검색하되, 나이를 기준으로 내림차순 정렬해보자.

#작성코드 / 정답코드와 동일
SELECT 고객이름, 등급, 나이 FROM 고객 ORDER BY 나이 DESC;

 

 

예제 27

 주문 테이블에서 수량이 10개 이상인 주문의 주문고객, 주문제품, 수량, 주문일자를 검색해보자. 단, 주문제품을 기준으로 오름차순 정렬하고, 동일 제품은 수량을 기준으로 내림차순 정렬해보자.

#작성코드 / 정답코드와 동일
SELECT 주문고객, 주문제품, 수량, 주문일자 FROM 주문 WHERE 수량 >= 10 ORDER BY 주문제품 ASC, 수량 DESC;

 

 

집계 함수를 이용한 검색

 특정 속성 값을 통계적으로 계산한 결과를 검색하기 위해 집계 함수(aggregate function)를 이용할 수 있다. 집계 함수는 열 함수(column function)라고도 하며 개수, 합계, 평균, 최댓값, 최솟값의 계산 기능을 제공한다. SUM과 AVG 함수는 숫자 데이터 타입의 속성에만 적용할 수 있고, 나머지 함수는 숫자 뿐 아니라 문자와 날짜 데이터 타입의 속성에도 적용할 수 있다.

 

집계 함수

 

 

집계 함수를 사용할 때 주의해야 할 두 가지 사항

 

1. 집계 함수는 널인 속성 값은 제외하고 계산한다.

2. 집계 함수는 WHERE 절에서는 사용할 수 없고 SELECT 절이나 HAVING 절에서만 사용할 수 있다.

 

예제 28

 제품 테이블에서 모든 제품의 단가 평균을 검색해보자.

#작성코드
SELECT AVG(단가) AS '단가 평균' FROM 제품;
#정답코드
SELECT AVG(단가) FROM 제품;

 

 

예제 29

 한빛제과에서 제조한 제품의 재고량 합계를 제품 테이블에서 검색해보자.

#작성코드 / 정답코드와 동일
SELECT SUM(재고량) AS '재고량 합계' FROM 제품 WHERE 제조업체 = '한빛제과';

 

 

 COUNT 함수는 다른 함수와 달리 테이블의 모든 속성에 적용하여 개수를 계산할 수 있다.

 

예제 30

 고객 테이블에 고객이 몇 명 등록되어 있는지 검색해보자.

#작성코드
SELECT COUNT(고객아이디) FROM 고객;
#정답코드

#고객아이디 속성을 이용해 계산하는 경우
SELECT COUNT(고객아이디) FROM 고객;

#나이 속성을 이용해 계산하는 경우
SELECT COUNT(나이) FROM 고객;

#*를 이용해 계산하는 경우
SELECT COUNT(*) FROM 고객;

 

 COUNT 함수의 경우 어떤 속성을 기준으로 잡느냐에 따라 검색이 가능하다. 고객아이디 속성과 나이 속성을 이용해 고객의 수를 계산하는 과정을 보면 결과가 다르다. 그 이유는 집계 함수는 널 인 속성 값은 제외하기 때문이다.

 

 COUNT(*)의 결과는 테이블에 있는 모든 튜플의 개수를 반환한다. 개수를 정확히 계산하려면 널 값이 없는 속성에 COUNT 함수를 적용하는 것이 좋기 때문에 보통 기본키 속성이나 *를 이용해 계산한다.

 

 

 DISTINCT 키워드를 사용해 특정 속성 값의 중복을 없애고 집계 함수를 적용할 수도 있다.

 

예제 31

 제품 테이블에서 제조업체의 수를 검색해보자.

#작성코드
SELECT COUNT(DISTINCT 제조업체) FROM 제품;
#정답코드
SELECT COUNT(DISTINCT 제조업체) AS '제조업체의 수' FROM 제품;

 

 

그룹별 검색

 테이블에서 특정 속성의 값이 같은 튜플을 모아 그룹을 만들고, 그룹별로 검색을 하기 위해 GROUP BY 키워드를 사용한다. 그룹에 대한 조건을 추가하려면 GROUP BY 키워드를 HAVING 키워드와 함께 사용하면 된다. GROUP BY 키워드가 없는 SELECT 문은 테이블 전체를 하나의 그룹으로 보고 검색하는 것이다.

SELECT

 

 GROUP BY 키워드와 함께 그룹을 나누는 기준이 되는 속성을 지정한다. 그리고 그룹에 대한 조건은 HAVING 키워드와 함께 작성한다.

 

예제 32

 주문 테이블에서 주문제품별 수량의 합계를 검색해보자.

#작성코드
SELECT 수량 FROM 주문 GROUP BY 수량 HAVING 주문제품;
#정답코드
SELECT 주문제품, SUM(수량) AS 총주문수량 FROM 주문 GROUP BY 주문제품;

 

  주문제품별 수량의 합계를 구하기 위해 동일 제품을 주문한 튜플을 모아 그룹을 만들고, 그룹별로 수량의 합계를 계산한다. 그룹별로 검색할 때는 그룹을 나누는 기준이 되는 속성을 SELECT 절에도 작성하는 것이 좋다. SELECT 절에 그룹을 나누는 기준 속성을 작성하지 않아도 실행은 되지만 어떤 그룹에 대한 검색 결과인지를 결과 테이블에서 확인하기 어렵기 때문이다.

 

 

예제 33

 제품 테이블에서 제조업체별로 제조한 제품의 개수와 제품 중 가장 비싼 단가를 검색하되, 제품의 개수를 제품수라는 이름으로 출력하고 가장 비싼 단가는 최고가라는 이름으로 출력해보자.

#작성코드
SELECT 제조업체, COUNT(재고량) AS 제품수, MAX(단가) AS 최고가 FROM 제품 GROUP BY 제조업체;
#정답코드
SELECT 제조업체, COUNT(*) AS 제품수, MAX(단가) AS 최고가 FROM 제품 GROUP BY 제조업체;

 

 일반적인 검색 조건은 WHERE 절에 작성하지만 그룹에 대한 조건은 HAVING 절에 작성한다. 앞서 설명한 집계 함수는 WHERE 절에는 사용할 수 없지만 HAVING 절에는 사용할 수 있다.

 

 

예제 34

 제품 테이블에서 제품을 3개 이상 제조한 제조업체별로 제품의 개수와, 제품 중 가장 비싼 단가를 검색해보자.

#작성코드
SELECT 제조업체, COUNT(*) AS 제품수, MAX(단가) AS 최고가 FROM 제품 COUNT(*) >= 3 GROUP BY 제조업체;
#정답코드
SELECT 제조업체, COUNT(*) AS 제품수, MAX(단가) AS 최고가 FROM 제품 GROUP BY 제조업체 HAVING COUNT(*) >= 3;

 

 HAVING 키워드를 사용하여 조건을 작성해야 된다는 것을 기억하자.

 

 

예제 35

 고객 테이블에서 적립금 평균이 1,000원 이상인 등급에 대해 등급별 고객수와 적립금 평균을 검색해보자.

#작성코드 / 정답코드와 동일
SELECT 등급, COUNT(*) AS 고객수, AVG(적립금) AS 평균적립금 FROM 고객 GROUP BY 등급 HAVING AVG(적립금) >= 1000;

 

 그룹별로 검색할 때는 집계 함수나 GROUP BY 절에 있는 속성 외의 속성은 SELECT 절에 사용할 수 없다.

#잘못된 코드
SELECT 주문제품, 주문고객, SUM(수량) AS 총주문수량 FROM 주문 GROUP BY 주문제품;

 

 GROUP BY 절에 없는 주문고객 속성이 SELECT에 사용되었기 때문에 오류가 발생한다. 이를 해결하기 위해 GROUP BY 절에 주문고객 속성을 추가해야 한다.

 

예제 36

 주문 테이블에서 각 주문고객이 주문한 제품의 총주문수량을 주문제품별로 검색해보자.

#작성코드 / 정답코드와 동일
SELECT 주문제품, 주문고객, SUM(수량) AS 총주문수량 GROUP BY 주문제품, 주문고객;

 

 예제 36에서 주문제품을 기준으로 하여 1차로 그룹을 나누고, 각 그룸에서 주문고객별로 더 작게 2차로 그룹 지어 수량의 합계를 계산한다. GROUP BY 절에는 그룹을 나누는 기준이 되는 주문제품과 주문고객 속성을 순서대로 작성한다.

 

여러 테이블에 대한 조인 검색

 여러 개의 테이블을 연결하여 데이터를 검색하는 것을 조인 검색이라 한다. 조인 검색을 하려면 테이블을 연결해주는 속성이 필요하고 이 속성을 조인 속성이라 한다. 테이블을 연결하려면, 조인 속성의 이름은 달라도 되지만 도메인은 반드시 같아야 한다. 일반적으로 테이블의 관계를 나타내는 외래키를 조인 속성으로 이용한다.

 

 

2개의 테이블을 이용한 조인 검색 예 : 주문과 제품 테이블

 

 

 예를 들어 banana 고객이 주문한 제품의 제품명을 검색하려면 제품과 주문 테이블이 필요하다. 검색에 필요한 주문고객 속성은 주문 테이블에 있지만 제품명 속성은 제품 테이블에 있기 때문이다. 두 테이블을 연결하려면 공통으로 가지고 있는 조인 속성이 필요하다. 여기서는 주문제품 속성과 제품번호 속성이 조인 속성의 역할을 한다.

 

 조인 검색을 위한 SQL 문은 FROM 절에 검색에 필요한 모든 테이블을 나열하고, WHERE 절에는 조인 속성의 값이 같아야 함을 의미하는 조인 조건을 제시한다. 여러 테이블을 이용하는 조인 검색의 특성상 이름이 같은 속성이 존재할 수 있기 때문에 속성의 이름 앞에 해당 속성이 소속된 테이블의 이름을 표시해주는 것이 좋다. 예를 들어, '주문.주문고객'은 주문 테이블에 있는 주문고객 속성을 의미한다.

 

예제 37

 판매 데이터베이스에서 banana 고객이 주문한 제품의 이름을 검색해보자.

#작성코드
SELECT 주문고객, 제품명 FROM 주문, 제품 WHERE 주문고객 = 'banana' AND 주문.주문제품 = 제품.제품번호;
#정답코드
SELECT 제품.제품명 FROM 제품, 주문 WHERE 주문.주문고객 = 'banana' AND 제품.제품번호 = 주문.주문제품;

 

 원하는 정보가 잘 나와서 좋아했는데, 두 개 이상의 테이블을 사용하다보니 속성이 소속된 테이블의 이름을 표시해주는 것이 좋다는 사실을 잊고 말았다.

#다시 작성한 코드
SELECT 주문.주문고객 AS 주문고객, 제품.제품명 AS 제품명 FROM 주문, 제품 WHERE 주문.주문고객 = 'banana' AND 주문.주문제품 = 제품.제품번호;

 

 속성이 소속된 테이블의 이름을 표시해주었고, 단순히 'banana' 고객이 주문한 제품명을 보여주는 것이 아닌, 주문고객의 이름까지 테이블에서 확인할 수 있게끔 코드를 작성했음.

 

 

예제 38

 판매 데이터베이스에서 나이가 30세 이상인 고객이 주문한 제품의 주문제품과 주문일자를 검색해보자.

#작성코드
SELECT 주문.주문고객, 고객.나이, 주문.주문제품, 주문.주문일자 FROM 주문, 고객 WHERE 주문.주문고객 = 고객.고객아이디 AND 고객.나이 >= 30;
#정답코드
SELECT 주문.주문제품, 주문.주문일자 FROM 고객, 주문 WHERE 고객.나이 >= 30 AND 고객.고객아이디 = 주문.주문고객;

 

 정답코드보다 더 식별하기 쉬운 코드를 작성했다고 생각함.

 

 테이블 이름이 길면 속성 이름 앞에 소속 테이블을 표기하는 일이 번거로울 수 있다. 이 경우 테이블의 이름을 대신하는 단순한 별명을 사용할 수 있다. FROM 절에 테이블의 이름과 별명을 함께 제시하면 된다.

SELECT 주문제품, 주문일자 FROM 고객 c, 주문 o WHERE c.나이 >= 30 AND o.주문고객 = c.고객아이디;

 

예제 39

 판매 데이터베이스에서 고명석 고객이 주문한 제품의 제품명을 검색해보자.

#작성코드
SELECT 고객이름, 제품명 FROM 고객 c, 제품 p, 주문 o WHERE c.고객이름 = '고명석' AND c.고객아이디 = o.주문고객 AND o.주문제품 = p.제품번호;
#정답코드
SELECT 제품.제품명 FROM 고객, 제품, 주문 WHERE 고객.고객이름 = '고명석' AND 고객.고객아이디 = 주문.주문고객 AND 제품.제품번호 = 주문.주문제품;

 

 큰 차이는 없으나 테이블의 별명을 함께 제시하여 작성해봤음.

 

부속 질의문을 이용한 검색

 SELECT 문 안에 또 다른 SELECT 문을 포함할 수 있다. 이를 부속 질의문 또는 서브 질의문이라 한다. 그리고 이 질의문을 포함하는 SELECT 문을 상위 질의문 또는 주 질의문이라 한다. 부속 질의문은 괄호로 묶어 작성하고 ORDER BY 절을 사용할 수 없으며, 상위 질의문보다 먼저 수행된다.

 

부속 질의문과 상위 질의문을 연결하는 연산자가 필요한데 부속 질의문의 종류에 따라 사용할 수 있는 연산자가 다르므로 주의해야 한다. 단일 행 부속 질의문은 일반 비교 연산자를 사용할 수 있지만, 다중 행 부속 질의문은 일반 비교 연산자를 사용할 수 없다.

 

예제 40

 판매 데이터베이스에서 달콤비스킷을 생산한 제조업체가 만든 제품들의 제품명과 단가를 검색해보자.

#작성코드
SELECT 제조업체, 제품명, 단가 FROM 제품 WHERE 제품명 = '달콤비스킷';
#정답코드
SELECT 제조업체, 제품명, 단가 FROM 제품 WHERE 제조업체 = (SELECT 제조업체 FROM 제품 WHERE 제품명 = '달콤비스킷');

 

 부속질의문 : '달콤비스킷'을 제조한 제조업체

 상위질의문 : 부속질의문을 만족하는 제조업체

 

 

예제 41

 판매 데이터베이스에서 적립금이 가장 많은 고객의 고객이름과 적립금을 검색해보자.

#작성코드 / 정답코드와 동일
SELECT 고객이름, 적립금 FROM 고객 WHERE 적립금 = (SELECT MAX(적립금) FROM 고객);

 

 처음에 WHERE 절에서 고객이름 = (SELECT 적립금 FROM 고객 WHERE MAX(적립금)); 으로 작성했는데 에러가 발생했다. 알아보니 WHERE 절에서는 집계 함수를 사용할 수 없다고 한다.

 

 

예제 42

 판매 데이터베이스에서 banana 고객이 주문한 제품의 제품명과 제조업체를 검색해보자.

#작성코드
SELECT 주문.주문고객, 제품.제품명, 제품.제조업체 FROM 주문, 제품 WHERE 주문.주문제품 = 제품.제품번호 AND 주문.주문고객 = 'banana';
#정답코드
SELECT 제품명, 제조업체 FROM 제품 WHERE 제품번호 IN (SELECT 주문제품 FROM 주문 WHERE 주문고객 = 'banana');
#다시 작성한 코드
SELECT DISTINCT 주문고객, 제품명, 제조업체 FROM 주문, 제품 WHERE 주문고객 = 'banana' AND 제품번호 IN (SELECT 주문제품 FROM 주문 WHERE 주문고객 = 'banana');

 

 부속 질의문을 사용하되, 주문고객의 이름인 'banana'를 같이 띄우고 싶었음. 이 과정에서 상위 질의문 주문고객 속성 앞에 DISTINCT 를 안 붙이니 이유는 모르겠지만 중복된 튜플이 3개씩 나오는 걸 확인할 수 있었음.

 

 

예제 43

 판매 데이터베이스에서 banana 고객이 주문하지 않은 제품의 제품명과 제조업체를 검색해보자.

#작성코드
SELECT 제품명, 제조업체 FROM 제품 WHERE 제품번호 IN (SELECT 주문제품 FROM 주문 WHERE 주문고객 != 'banana');
#정답코드
SELECT 제품명, 제조업체 FROM 제품 WHERE 제품번호 NOT IN (SELECT 주문제품 FROM 주문 WHERE 주문고객 = 'banana');

 

 

다중 행 부속 질의문에 사용 가능한 연산자

 

 

예제 44

 판매 데이터베이스에서 대한식품이 제조한 모든 제품의 단가보다 비싼 제품의 제품명, 단가, 제조업체를 검색해보자.

#작성코드
SELECT 제품명, 단가, 제조업체 FROM 제품 WHERE 단가 > (SELECT MAX(단가) FROM 제품 WHERE 제조업체 = '대한식품');
#정답코드
SELECT 제품명, 단가, 제조업체 FROM 제품 WHERE 단가 > ALL (SELECT 단가 FROM 제품 WHERE 제조업체 = '대한식품');

 

 출력 결과는 동일하게 나왔음. 어차피 대한식품이 제조한 모든 제품의 단가보다 비싸다는 것은 단가가 제일 비싼 제품만 고려하면 된다고 생각했음. 하지만 다중 행 부속 질의문에서 사용 가능한 연산사를 학습하기엔 정답코드가 더 유용한 듯 함.

 

 

예제 45

 판매 데이터베이스에서 2019년 3월 15일에 제품을 주문한 고객의 고객이름을 검색해보자.

#작성코드
SELECT 고객이름 FROM 고객 WHERE 고객아이디 IN (SELECT 주문고객 FROM 주문 WHERE 주문일자 = '2019-03-15');
#정답코드
SELECT 고객이름 FROM 고객 WHERE EXISTS (SELECT * FROM 주문 WHERE 주문일자 = '2019-03-15' AND 주문.주문고객 = 고객.고객아이디);

 

 실습하면서 느낀 건데, 상위 질의문의 WHERE 절과 부속 질의문이 서로 다른 테이블에 있어도 알아서 참조가 되는 듯 싶음.

 

 

예제 46

 판매 데이터베이스에서 2019년 3월 15일에 제품을 주문하지 않은 고객의 고객이름을 검색해보자.

#작성코드 / 정답코드와 동일
SELECT 고객이름 FROM 고객 WHERE NOT EXISTS (SELECT 주문고객 FROM 주문 WHERE 주문일자 = '2019-03-15' AND 주문.주문고객 = 고객.고객아이디);

 

 

데이터 삽입

 테이블에 새로운 튜플을 삽입하기 위해 필요한 SQL 문은 INSERT다. INSERT 문을 이용해 튜플을 삽입하는 방법은 두 가지가 있다. 첫 번째는 테이블에 튜플을 직접 삽입하는 방법이고, 둘째는 부속 질의문을 이용해 튜플을 삽입하는 방법이다.

 

데이터 직접 삽입

 

#기본형식
INSERT INTO 테이블_이름[(속성_리스트)] VALUES 속성값(속성값_리스트);

INSERT INTO 테이블_이름(속성_리스트) VALUES (속성값_리스트);

INSERT INTO 테이블_이름(가, 나, 다, 라, 마) VALUES ('1', 2, '3', '4', 5);

 

예제 47

 판메 데이터베이스의 고객 테이블에 고객아이디가 strawberry, 고객이름이 최유경, 나이가 30세, 등급이 vip, 직업이 공무원, 적립금이 100원인 새로운 고객의 정보를 삽입해보자. 그런 다음 고객 테이블에 있는 모든 내용을 검색하여 삽입된 새로운 튜플을 확인해보자.

#작성코드
INSERT INTO 고객(고객아이디, 고객이름, 나이, 등급, 직업, 적립금) VALUES ('strawberry', '최유경', 30, 'vip', '공무원', 100);
SELECT * FROM 고객;

 

 속성 이름과 속성 값은 일대일 대응 관계가 되야 한다.

 

 

예제 48

 판매 데이터베이스의 고객 테이블에 고객아이디가 tomato, 고객이름이 정은심, 나이가 36세, 등급이 gold, 적립금은 4,000원, 직업은 아직 모르는 새로운 고객의 정보를 삽입해보자. 그런 다음 고객 테이블에 있는 모든 내용을 검색하여, 삽입된 정은심 고객의 직업 속성이 널 값인지 확인해보자.

#작성코드 / 정답코드와 동일
INSERT INTO 고객(고객아이디, 고객이름, 나이, 등급, 적립금) VALUES ('tomato', '정은심', 36, 'gold', 4000);
SELECT * FROM 고객;

 

 

부속 질의문을 이용한 데이터 삽입

#기본코드
INSERT INTO 테이블_이름[(속성_리스트)] SELECT 문;

 

 

 제품명, 재고량, 단가 속성으로 구성된 한빛제품 테이블이 존재한다고 가정하고, 부속 질의문을 이용한 INSERT 문의 예를 살펴보자.

INSERT INTO 한빛제품(제품명, 재고량, 단가) SELECT 제품명, 재고량, 단가 FROM 제품 WHERE 제조업체 = '한빛제과';

 

 

데이터의 수정

#기본코드
UPDATE 테이블_이름 SET 속성_이름1 = 값1, 속성_이름2 = 값2, ..., 속성_이름n = 값n WHERE 조건;

 

예제 49

 제품 테이블에서 제품번호가 p03인 제품의 제품명을 통큰파이로 수정해보자.

#작성코드
UPDATE 제품 SET 제품번호 = 'p03' WHERE 제품명 = '통큰파이';
#정답코드
UPDATE 제품 SET 제품명 = '통큰파이' WHERE 제품번호 = 'p03';
SELECT * FROM 제품;

 

 

예제 50

 제품 테이블에 있는 모든 제품의 단가를 10% 인상해보자. 그런 다음 제품 테이블의 모든 내용을 검색하여 인상 내용을 확인해보자.

#작성코드
UPDATE 제품 SET 단가 * 1.1;
SELECT * FROM 제품;
#정답코드
UPDATE 제품 SET 단가 = 단가 * 1.1;
SELECT * FROM 제품;

 

 

예제 51

 판매 데이터베이스에서 정소화 고객이 주문한 제품의 주문수량을 5개로 수정해보자. 그런 다음 주문 테이블의 모든 내용을 검색하여 수정 내용을 확인해보자.

#작성코드 / 정답코드와 동일
UPDATE 주문 SET 수량 = 5 WHERE 주문고객 IN (SELECT 고객아이디 FROM 고객 WHERE 고객이름 = '정소화');
SELECT * FROM 주문;

 

 

데이터의 삭제

#기본코드
DELETE FROM 테이블_이름 WHERE 조건;

 

예제 52

 주문 테이블에서 주문일자가 2019년 5월 22일 주문내역을 삭제해보자. 그런 다음 주문 테이블의 모든 내용을 검색하여 삭제 여부를 확인해보자.

#작성코드 / 정답코드와 동일
DELETE FROM 주문 WHERE 주문일자 = '2019-05-22';
SELECT * FROM 주문;

 

 

예제 53

 판매 데이터베이스에서 정소화 고객이 주문한 내역을 주문 테이블에서 삭제해보자. 그런 다음 주문 테이블의 모든 내용을 검색하여 삭제 여부를 확인해보자.

#작성코드 / 정답코드와 동일
DELETE FROM 주문 WHERE 주문고객 IN (SELECT 고객아이디 FROM 고객 WHERE 고객이름 = '정소화');
SELECT * FROM 주문;

 

 

예제 54

 판매 데이터베이스에서 주문 테이블에 존재하는 모든 튜플을 삭제해보자. 그런 다음 주문 테이블의 모든 내용을 검색하여 삭제 여부를 확인해보자.

#작성코드 / 정답코드와 동일
DELETE FROM 주문;
SELECT * FROM 주문;

'데이터베이스 > 데이터베이스 언어 SQL' 카테고리의 다른 글

삽입 SQL  (0) 2024.06.06
  (0) 2024.06.06
SQL을 이용한 데이터 정의  (0) 2024.06.01
SQL의 소개  (0) 2024.06.01
2024-06-01 16:07:44

SQL의 데이터 정의 기능

 SQL의 데이터 정의 기능은 테이블 생성, 생성된 테이블 구조의 변경, 테이블 제거로 분류할 수 있다.

 

 

SQL의 데이터 정의 기능

 

 

테이블의 생성

 새로운 테이블을 생성하려면 먼저 테이블의 이름과 테이블을 구성하는 속성의 이름을 의미있게 정해야 한다. 그런 다음 각 속성의 특성에 맞게 데이터 타입을 결정한다.

 

 다음 CREATE TABLE 문의 기본 형식에서 ❶은 테이블을 구성하는 각 속성의 이름과 데이터 타입, 기본적인 제약 사항을 정의한다. ❷는 기본키로 테이블에 하나만 존재할 수 있다. ❸은 대체키로 테이블에 여러 개 존재할 수 있다. ❹는 외래키로 테이블에 여러 개 존재할 수 있다. ❺는 데이터 무결성을 위한 제약조건으로 테이블에 여러 개 존재할 수 있다. 그리고 []로 표시한 항목은 생략이 가능하다.

 

 

 

 모든 SQL 문은 세미콜론(;)으로 문장 끝을 표시한다. 그리고 SQL 문에 사용되는 CREATE TABLE, NOT NULL과 같은 키워드는 대소문자를 구분하지 않는다. 실제로 DB를 구축할 때는 보통 테이블 이름과 속성 이름을 영어로 작성하지만 이 장에서는 좀 더 직관적으로 이해할 수 있도록 테이블과 속성을 한글 이름으로 작성한 예를 통해 설명한다.

 

속성의 정의

 CREATE TABLE 문으로 생성되는 테이블을 구성하는 속성은 기본적으로 널 값이 허용된다. 만약 널 값을 허용하지 않으려면 속성을 정의할 때 속성의 이름과 데이터 타입 다음에 NOT NULL 키워드를 포함해야 한다. 특히, 기본키를 구성하는 모든 속성은 널 값을 가질 수 없도록 반드시 NOT NULL 키워드를 표기한다.

 

속성의 데이터 타입

 

 

 기본키를 구성하는 속성이 아니더라도 값을 꼭 입력해야 된다고 판단되는 속성은 NOT NULL 키워드를 표기한다.

 

예) 고객아이디 VARCHAR(20) NOT NULL

-> 고객 테이블의 고객아이디 속성을 길이가 최대 20인 가변 길이의 문자열 데이터로 구성하고, 널 값을 허용하지 않음.

 

 

 속성에 기본 값을 지정해두지 않으면 사용자가 속성에 값을 입력하지 않았을 때 해당 속성에 널 값이 기본으로 저장된다. 하지만 DEFAULT 키워드를 사용해 기본 값을 명확히 지정해두면 이 기본 값이 저장된다.

 

예) 적립금 INT DEFAULT 0

-> 고객 테이블의 적립금 속성을 정수 데이터로 구성하고, 사용자가 적립금을 입력하지 않으면 0이 기본 저장되도록 함.

 

 DEFAULT 키워드로 기본 값을 지정할 때 숫자 데이터는 그대로 표현하고, 문자열이나 날짜 데이터는 작은따옴표로 묶어주어야 한다. 작은따옴표로 묶인 문자열은 대소문자를 구분한다.

 

키의 정의

 CREATE TABLE 문으로 테이블을 정의할 때는 기본키, 대체키, 외래키를 지정할 수 있다.

 

 기본키는 PRIMARY KEY 키워드를 사용해 지정한다. 기본키가 없어도 테이블을 정의할 수 있지만 각 튜플을 식별할 수 있는 기본키는 가능한 한 선택하는 것이 좋다. 모든 테이블에서 기본키는 반드시 하나만 지정할 수 있고, 여러 개의 속성으로 구성할 수도 있다.

 

예) PRIMARY KEY(고객아이디)

-> 고객아이디 속성을 기본키로 지정함

 

예) PRIMARY KEY(주문고객, 주문제품)

-> 주문고객, 주문제품 속성을 기본키로 지정함

 

 

 대체키는 UNIQUE 키워드를 사용해 지정한다. 대체키는 기본키와 같이 각 튜플을 유일하게 식별하는 특성이 있다. 대체키로 지정된 속성의 값은 테이블에서 중복되면 안 되고 유일성을 가져야 한다. 하지만 기본키로 지정된 속성과 달리 널 값을 가질 수 있다. 또한 대체키는 한 테이블에서 여러 개 지정할 수 있다.

 

예) UNIQUE(고객이름)

-> 고객이름 속성을 대체키로 지정함

 

 

 외래키는 FOREIGN KEY 키워드를 사용해 지정한다. 외래키는 지정할 때는 출처를 분명히 밝혀야 한다. 즉, 외래키가 어떤 테이블의 무슨 속성을 참조하는지 REFERENCES 키워드 다음에 명확히 제시해야 한다. 이렇게 하면 참조되는 테이블에서 튜플을 함부로 삭제하거나 변경하지 못한다. 그리고 참조되는 테이블에서 튜플을 삭제하거나 변경할 때 처리하는 방법을 다양하게 선택할 수 있다.

 

 외래키를 포함한 테이블을 정의하는 CREATE TABLE 문을 작성할 때 이 중 하나를 지정하면 되는데, 별도로 지정하지 않으면 ON DELETE NO ACTION이 기본으로 선택된다.

 

❶ ON DELETE NO ACTION : 튜플을 삭제하지 못하게 한다.

❷ ON DELETE CASCADE : 관련 튜플을 함께 삭제한다.

❸ ON DELETE SET NULL : 관련 튜플의 외래키 값을 NULL로 변경한다.

❹ ON DELETE SET DEFAULT : 관련 튜플의 외래키 값을 미리 지정한 기본 값으로 변경한다.

 

 참조되는 테이블의 튜플이 변경될 때도 다음 네 가지 중 한 가지 방법으로 처리하도록 선택할 수 있다. 외래키를 포함한 테이블을 정의하는 CREATE TABLE 문을 작성할 때 네 가지 방법 중 하나를 지정하면 되는데, 지정하지 않으면 ON UPDATE NO ACTION이 기본으로 선택된다.

 

❶ ON UPDATE NO ACTION : 튜플을 변경하지 못하도록 한다.

❷ ON UPDATE CASCADE : 관련 튜플에서 외래키 값을 함께 변경한다.

❸ ON UPDATE SET NULL : 관련 튜플의 외래키 값을 NULL로 변경한다.

❹ ON UPDATE SET DEFAULT : 관련 튜플의 외래키 값을 미리 지정한 기본 값으로 변경한다.

 

예) FOREIGN KEY(소속부서)    REFERENCES    부서(부서번호)

      ON DELETE CASCADE ON UPDATE CASCADE

-> 소속부서 속성이 부서 테이블의 부서번호 속성을 참조하는 외래키이고 ON DELETE CASCADE와 ON UPDATE CASCADE 방법으로 처리함

 

예) FOREIGN KEY(소속부서)    REFERENCES    부서(부서번호)

-> 소속부서 속성이 부서 테이블의 부서번호 속성을 참조하는 외래키이고 ON DELETE NO ACTION과 ON UPDATE NO ACTION 처리 방법이 자동으로 선택됨

 

 

데이터 무결성 제약조건의 정의

 CREATE TABLE 문으로 테이블을 정의할 때 CHECK 키워드를 사용해 특정 속성에 대한 제약조건을 지정할 수 있다. 그러면 테이블에는 CHECK 키워드로 지정한 제약조건을 만족하는 튜플만 존재하게 된다. 테이블에 새로운 튜플을 삽입하거나 기존 튜플을 수정할 때도 이 제약 조건을 반드시 지켜야 한다.

 

예) CHECK(재고량 >= 0 AND 재고량 <= 10000)

-> 모든 제품의 재고량은 항상 0개 이상, 10,000개 이하로 유지되어야 한다는 데이터 무결성 제약조건

 

CHECK 키워드를 사용해 지정한 제약조건에 CONSTRAINTS 키워드와 함께 고유의 이름을 부여할 수도 있다. 제약조건을 여러 개 지정할 때 고유의 이름을 부여하면 테이블이 생성된 이후에 제약조건을 수정하거나 제거할 때 식별하기가 쉽다.

 

예) CONSTRAINTS CHK_CPY CHECK(제조업체 = '한빛제과')

-> 모든 제품의 제조업체로 한빛제과만 허용된다는 데이터 무결성 제약조건에 CHK_CPY이라는 고유의 이름을 부여함. 다른 테이블에는 CHK_CPY이라는 이름으로 정의된 제약조건이 있으면 안 됨

 

 

테이블 생성의 예

 

 예제 1

 고객 테이블은 고객아이디, 고객이름, 나이, 등급, 직업, 적립금 속성으로 구성되고, 고객아이디 속성이 기본키다. 고객이름과 등급 속성은 값을 반드시 입력해야 하고, 적립금 속성은 값을 입력하지 않으면 0이 기본으로 입력되도록 고객 테이블을 생성해보자.

#작성 코드
CREATE TABLE 고객 (
    고객아이디 VARCHAR(20) NOT NULL,
    고객이름 VARCHAR(20) NOT NULL,
    나이 INT,
    등급 VARCHAR(20) NOT NULL,
    직업 VARCHAR(20),
    적립금 INT,
    PRIMARY KEY(고객아이디),
);
#정답코드
CREATE TABLE 고객 (
    고객아이디 VARCHAR(20) NOT NULL,
    고객이름 VARCHAR(10) NOT NULL,
    나이 INT,
    등급 VARCHAR(10) NOT NULL,
    직업 VARCHAR(20),
    적립금 INT DEFAULT 0,
    PRIMARY KEY(고객아이디)
);

 

 DEFAULT 키워드를 사용해 기본 값을 지정할 수 있음을 기억하자.

 

 

예제 2

 제품 테이블은 제품번호, 제품명, 재고량, 단가, 제조업체 속성으로 구성되고, 제품번호 속성이 기본키다. 재고량이 항상 0개 이상 10,000개 이하를 유지하도록 제품 테이블을 생성해보자.

#작성코드
CREATE TABLE 제품 (
    제품번호 INT NOT NULL,
    제품명 VARCHAR(20),
    재고량 INT,
    단가 INT,
    제조업체 VARCHAR(20),
    PRIMARY KEY(제품번호)
);
#정답코드
CREATE TABLE 제품 (
    제품번호 CHAR(3) NOT NULL,
    제품명 VARCHAR(20),
    재고량 INT,
    단가 INT,
    제조업체 VARCHAR(20),
    PRIMARY KEY(제품번호),
    CHECK (재고량 >= 0 AND 재고량 <= 10000)
);

 

 CHECK 키워드를 사용해 특정 속성에 대한 제약조건을 지정할 수 있음을 기억하자.

 

 

예제 3

 주문 테이블은 주문번호, 주문고객, 주문제품, 수량, 배송지, 주문일자 속성으로 구성되고, 주문번호 속성이 기본키다. 주문고객 속성이 고객 테이블의 고객아이디 속성을 참조하는 외래키이고, 주문제품 속성이 제품 테이블의 제품번호 속성을 참조하는 외래키가 되도록 주문 테이블을 생성해보자.

#작성코드
CREATE TABLE 주문 (
    주문번호 VARCHAR(20) NOT NULL,
    주문고객 VARCHAR(20),
    주문제품 VARCHAR(10),
    수량 INT,
    배송지 VARCHAR(20),
    주문일자 VARCHAR(20),
    PRIMARY KEY(주문번호),
    FORIGEN KEY(주문고객)
);
#정답코드
CREATE TABLE 주문 (
    주문번호 CHAR(3) NOT NULL,
    주문고객 VARCHAR(20),
    주문제품 CHAR(3),
    수량 INT,
    배송지 VARCHAR(30),
    주문일자 DATE,
    PRIMARY KEY(주문번호),
    FORIGEN KEY(주문고객) REFERENCES 고객(고객아이디),
    FORIGEN KEY(주문제품) REFERENCES 제품(제품번호)
);

 

 날짜의 경우 데이터 타입으로 DATE 를 사용한다. 참조한다는 뜻을 가진 REFERENCES 키워드를 기억하자.

 

 

예제 4

 배송업체 테이블은 업체번호, 업체명, 주소, 전화번호 속성으로 구성되고 업체번호 속성이 기본키다. 배송업체 테이블을 생성해보자.

#작성코드
CREATE TABLE 배송업체 (
    업체번호 CHAR(3) NOT NULL,
    업체명 VARCHAR(20),
    주소 VARCHAR(30),
    전화번호 VARCHAR(20),
    PRIMARY KEY(업체번호)
);
#정답코드
CREATE TABLE 배송업체 (
    업체번호 CHAR(3) NOT NULL,
    업체명 VARCHAR(20),
    주소 VARCHAR(100),
    전화번호 VARCHAR(20),
    PRIMARY KEY(업체번호)
);

 

 

테이블의 변경

 테이블은 ALTER TABLE 문으로 변경할 수 있다. ALTER TABLE 문을 이용해 새로운 속성 추가, 기존 속성 삭제, 새로운 제약조건 추가, 기존 제약조건 삭제 등이 가능하다.

 

새로운 속성의 추가

 테이블에 새로운 속성을 추가하는 ALTER TABLE 문의 기본 형식은 다음과 같다.

ALTER TABLE 테이블_이름
    ADD 속성_이름 데이터_타입 [NOT NULL] [DEFAULT 기본_값];

 

예제 5

 예제 1에서 생성한 고객 테이블에 가입날짜 속성을 추가해보자.

#작성코드
ALTER TABLE 고객
    ADD 가입날짜 DATE [NOT NULL];
#정답코드
ALTER TABLE 고객 ADD 가입날짜 DATE;

 

 [NOT NULL] 과 [DEFAULT 기본_값] 은 주어진 조건이 없으면 사용하지 않아도 된다.

 

 

기존 속성의 삭제

 테이블의 기존 속성을 삭제하는 ALTER TABKE 문의 기본 형식은 다음과 같다.

ALTER TABLE 테이블_이름 DROP COLUMN 속성_이름;

 

 만약 삭제할 속성과 관련된 제약조건이 존재하거나 이 속성을 참조하는 다른 속성이 존재하는 경우에는 속성을 삭제할 수 없다. 관련된 제약조건이나 참조하는 다른 속성을 먼저 삭제한 후 해당 속성을 삭제해야 한다.

 

예제 6

 예제 1에서 생성한 고객 테이블의 가입날짜 속성을 삭제해보자.

#작성코드 / 정답코드와 동일
ALTER TABLE 고객 DROP COLUMN 가입날짜 ;

 

 

새로운 제약조건의 추가

 테이블에 새로운 제약조건을 추가하는 ALTER TABLE 문의 기본 형식은 다음과 같다.

ALTER TABLE 테이블_이름 ADD CONSTRAINT 제약조건_이름 제약조건_내용 ;


예제 7

 고객 테이블에 20세 이상의 고객만 가입할 수 있다는 데이터 무결성 제약조건을 추가해보자.

#작성코드
ALTER TABLE 고객 ADD CONSTRAINT AGE_LIMIT AGE >= 20 ;
#정답코드
ALTER TABLE 고객 ADD CONSTRAINT CHK_AGE CHECK(나이 >= 20) ;

 

 제약조건을 지정할 때 CHECK 키워드를 사용한다는 것을 다시금 기억하자.

 

 

기존 제약조건의 삭제

 테이블의 기존 제약조건을 삭제하는 ALTER TABLE 문의 기본 형식은 다음과 같다.

ALTER TABLE 테이블_이름 DROP CONSTRAINT 제약조건_이름 ;

 

예제 8

 예제 7에서 추가한 고객 테이블에 20세 이상의 고객만 가입할 수 있다는 데이터 무결성 제약조건을 삭제해보자.

#작성코드 / 정답코드와 동일
ALTER TABLE 고객 DROP CONSTRAINT CHK_AGE ;

 

 

테이블의 삭제

 CREATE TABLE 문으로 생성한 테이블은 DROP TABLE 명령어로 삭제할 수 있다. 테이블을 삭제하는 DROP TABLE 문의 기본 형식은 다음과 같다.

DROP TABLE 테이블_이름 ;

 

 삭제할 테이블을 참조하는 테이블이 있다면 삭제가 수행되지 않는다. 따라서 삭제하고자 하는 테이블을 참조하는 외래키 제약조건을 먼저 삭제해야 한다.

 

예제 9

 배송업체 테이블을 삭제해보자.

#작성코드 / 정답코드와 동일
DROP TABLE 배송업체 ;

 

 예제 9번에서 배송업체 테이블을 참조하는 테이블이 없기에 문제없이 삭제된다. 하지만 고객 테이블은 주문 테이블이 참조하고 있어 삭제가 수행되지 않는다.

 


테이블 생성 CREATE TABLE

 

테이블 변경 ALTER TABLE

 

테이블 제거 DROP TABLE

 

널 값을 가질 수 없다 NOT NULL

 

기본 값 지정 DEFAULT

 

기본키 지정 PRIMARY KEY

 

외래키 지정 FOREIGN KEY

 

속성 참조 REFERENCES

 

제약조건 지정 CHECK

 

제약조건 고유의 이름 부여 CONSTRAINTS

'데이터베이스 > 데이터베이스 언어 SQL' 카테고리의 다른 글

삽입 SQL  (0) 2024.06.06
  (0) 2024.06.06
SQL을 이용한 데이터 조작  (0) 2024.06.02
SQL의 소개  (0) 2024.06.01
2024-06-01 15:19:01

 SQL은 기능에 따라 데이터 정의어(DDL), 데이터 조작어(DML), 데이터 제어어(DCL)로 나눈다.

 

SQL의 분류

 

 

데이터 정의어 : 테이블을 생성하고 변경, 제어하는 기능을 제공한다.

 

데이터 조작어 : 테이블에 새 데이터를 삽입하거나, 테이블에 저장된 데이터를 수정, 삭제, 검색하는 기능을 제공한다.

 

데이터 제어어 : 보안을 위해 데이터에 대한 접근 및 사용 권한을 사용자별로 부여하거나 취소하는 기능을 하는 언어다. DB 관리자가 주로 사용한다.

 

이 장에서는 다음 그림의 판매 DB를 예로 들어 SQL의 기능을 소개한다. 판매 DB는 고객, 제품, 주문 테이블(릴레이션)로 구성된다.

 

 

고객 테이블

 

제품 테이블

 

질의에 사용할 판매 데이터베이스 : 고객, 제품, 주문 테이블

 

'데이터베이스 > 데이터베이스 언어 SQL' 카테고리의 다른 글

삽입 SQL  (0) 2024.06.06
  (0) 2024.06.06
SQL을 이용한 데이터 조작  (0) 2024.06.02
SQL을 이용한 데이터 정의  (0) 2024.06.01