티스토리 뷰
SQL의 소개
SQL(Structured Query Language)은 관계 데이터베이스를 위한 표준 질의어로 많이 사용되는 언어다. SQL은 사용자가 처리를 원하는 데이터가 무엇인지 제시하고 데이터를 어떻게 처리해야 하는지를 언급할 필요가 없어 비절차적 데이터 언어의 특징을 띤다고 할 수 있다.
SQL은 데이터베이스 관리 시슽메에 직접 접근하여 대화식으로 질의를 작성해 사용할 수도 있고 C나 JAVA같은 언어로 작성한 응용 프로그램에 삽입하여 사용할 수도 있다.
이 장에서는 데이터 정의어와 데이터 조작어를 중심으로 공부하고, 데이터 제어어는 11장에서 따로 다룬다.
복습
SQL(데이터 언어라고 의미해도 무리는 없다)의 분류
데이터 정의어 : 테이블을 생성하고 변경 제거하는 기능을 제공한다.
데이터 조직어 : 테이블에 새 데이터를 삽입하거나, 테이블에 저장된 데이터를 수정 삭제 검색하는 기능을 제공한다.
데이터 제어어 : 보안을 위해 데이터에 대한 접근 및 사용 권한을 사용자별로 부여하거나 취소하는 기능을 제공하는 언어다. 데이터베이스 관리자가 주로 사용한다.
SQL을 이용한 데이터 정의
SQL의 데이터 정의 기능
테이블 생성 CREATE TABLE
테이블 변경 ALTER TABLE
테이블 삭제 DROP TABLE
테이블의 생성
CREATE TABLE 테이블_이름(
속성_이름 데이터_타입 [NOT NULL] [DEFAULT 기본_값]
[PRIMARY KEY(속성_리스트)]
[UNIQUE (속성_리스트)]
[FOREIGN KEY(속성_리스트) REFERENCES 테이블_이름(속성)리스트)]
[ON DELETE 옵션] [ON UPDATE 옵션]
[CONSTRAINT 이름] [CHECK(조건)]
);
기본키(PRIMARY KEY), 대체키(UNIQUE), 외래키(FOREIGN KEY)를 지정할 수 있다.
외래키가 어떤 테이블의 무슨 속성을 참조하는지 REFERENCES 키워드 다음에 명확히 제시해야 한다. 이렇게 하면 참조되는 테이블에서 투플을 함부로 삭제하거나 변경하지 못한다. 그리고 참조되는 테이블에서 투플을 삭제하거나 변경할 때 처리하는 방법을 다양하게 선택할 수 있다. DEFAULT는 ON DELETE NO ACTION
1. ON DELETE NO ACTION : 투플을 삭제하지 못하게 한다.
2. ON DELETE CASCADE : 관련 투플을 함께 삭제한다.
3. ON DELETE SET NULL : 관련 투플의 외래키 값을 NULL로 변경한다.
4. ON DELETE SET DEFAULT : 관련 투플의 외래키 값을 미리 지정한 기본 값으로 변경한다.
참조되는 테이블의 투플이 변경될 때도 다음 네 가지 중 한가지 방법으로 처리되도록 선택할 수 있다.
DEFAULT는 ON UPDATE NO ACTION
1. ON UPDATE NO ACTION : 투플을 변경하지 못하도록 한다.
2. ON UPDATE CASCADE : 관련 투플에서 외래키 값을 함께 변경한다.
3. ON UPDATE SET NULL : 관련 투플의 외래키 값을 NULL로 변경한다.
4. ON UPDATE SET DEFAULT : 관련 투플의 외래키 값을 미리 지정한 기본 값으로 변경한다.
CHECK 키워드를 사용해 특정 속성에 대한 제약조건을 지정할 수 있다. 테이블에 새로운 투플을 삽입하거나 기존 투플을 수정할 때도 이 제약 조건을 반드시 지켜야 한다. 이는 테이블에서 항상 정확하고 유효한 데이터를 유지하기 위해 데이터 무결성을 위한 제약조건을 표현하는 방법이다.
ex) CHECK(재고량>=0 AND 재고량<=10000)
CHECK 키워드를 사용해 지정한 제약조건에 CONSTRAINT 키워드와 함께 고유의 이름을 부여할 수도 있다. 제약조건을 여러 개 지정할 때 고유의 이름을 부여하면 테이블이 생성된 이후에 제약조건을 수정하거나 제거할 때 식별하기가 쉽다.
ex) CONSTRAINT CHK_CPY CHECK(제조업체='한빛제과')
테이블의 변경
테이블은 ALTER TABLE문으로 변경할 수 있다. ALTER TABLE 문을 이용해 새로운 속성 추가, 기존 속성 삭제, 새로운 제약조건 추가, 기존 제약조건 삭제 등이 가능하다.
1. 새로운 속성의 추가
ALTER TABLE 테이블_이름
ADD 속성_이름 데이터_타입 [NOT NULL] [DEFAULT 기본_값]
2. 기존 속성의 삭제
ALTER TABLE 테이블_이름 DROP COLUMN 속성_이름;
3. 새로운 제약조건의 추가
ALTER TABLE 테이블_이름 ADD CONSTRAINT 제약조건_이름 제약조건_내용
4. 기존 제약조건의 삭제
ALTER TABLE 테이블_이름 DROP CONSTRAINT 제약조건_이름;
테이블의 삭제
DROP TABLE 테이블_이름;
삭제할 테이블을 참조하는 테이블이 있다면 삭제가 수행되지 않는다. 따라서 삭제하고자 하는 테이블을 참조하는 외래키 제약조건을 먼저 삭제해야 한다.
SQL을 이용한 데이터 조작
SQL의 데이터 조작 기능
데이터 검색 SELECT
데이터 삽입 INSERT
데이터 수정 UPDATE
데이터 삭제 DELETE
데이터의 검색
CREATE TABLE 고객(
고객아이디 VARCHAR(20) NOT NULL,
고객이름 VARCHAR(10) NOT NULL,
나이 INT,
등급 VARCHAR(10) NOT NULL,
직업 VARCHAR(20),
적립금 INT DEFAULT 0,
PRIMARY KEY(고객아이디)
);
CREATE TABLE 제품(
제품번호 CHAR(3) NOT NULL,
제품명 VARCHAR(20),
재고량 INT ,
단가 INT,
제조업체 VARCHAR(20),
PRIMARY KEY(제품번호),
CHECK(재고량>=0 AND 재고량<=10000) //이거 한글이라 MYSQL에서 안돼(영어면 가능)
);
CREATE TABLE 배송업체(
업체번호 CHAR(3) NOT NULL,
업체명 VARCHAR(20),
주소 VARCHAR(100),
전화번호 VARCHAR(20),
PRIMARY KEY(업체번호)
);
CREATE TABLE 주문(
주문번호 CHAR(3) NOT NULL,
주문고객 VARCHAR(20),
주문제품 CHAR(3),
수량 INT,
배송지 VARCHAR(30),
주문일자 DATE,
PRIMARY KEY(주문번호),
FOREIGN KEY(주문고객) REFERENCES 고객(고객아이디),
FOREIGN KEY(주문제품) REFERENCES 제품(제품번호)
);
기본 검색
기본 검색을 위한 SELECT 문의 기본 형식
SELECT [ALL : DISTINCT] 속성_리스트 FROM 테이블_리스트;
ex) SELECT 고객아이디 FROM 고객;
SELECT * FROM 고객; 모든 속생 검색
SELECT ALL 제조업체 FROM 제품; 중복 허용
SELECT DISTINCT 제조업체 FROM 제품; 중복 없이
SELECT 제품명, 단가 AS 가격 FROM 제품; AS로 결과 테이블에 출력되는 속성의 이름을 변경(단가->가격)(AS 생략)
산술식을 이용한 검색
산술식은 속성의 이름과 +, -, *, / 등의 산술 연산자, 상수로 구성한다.
ex) SELECT 제품명, 단가+500 AS 조정단가 FROM 제품;
조건 검색
조건을 만족하는 데이터만 검색하는 SELECT문의 기본 형식은 다음과 같다.
SELECT [ALL : DISTINCT] 속성_리스트 FROM 테이블_리스트 [WHERE 조건 ];
비교 연산자 : =(같다), <>(다르다), <, <=,
논리 연산자 : AND, OR, NOT
ex) SELECT 주문제품, 수량, 주문일자 FROM 주문 WHERE 주문고객='apple' AND 수량>=15;
SELECT 주문제품, 수량, 주문일자, 주문고객 FROM 주문 WHERE 주문고객='apple' OR 수량>=15;
SELECT 제품명, 단가, 제조업체 FROM 제품 WHERE 단가>=2000 AND 단가<=3000;
LIKE를 이용한 검색
검색 조건을 부분적으로만 알고 있다면 LIKE 키워드를 이용해 검색할 수 있다.
ex) SELECT 고객이름, 나이, 등급, 적립금 FROM 고객 WHERE 고객이름 LIKE '김%';
SELECT 고객아이디, 고객이름, 등급 FROM 고객 WHERE 고객아이디 LIKE '_____';
NULL을 이용한 검색
검색 조건에서 특정 속성의 값이 널 값인지를 비교하려면 IS NULL 키워드를 사용한다. 반대로 특정 속성의 값이 널 값이 아닌지를 비교하려면 IS NOT NULL 키워드를 사용한다.
ex) SELECT 고객이름 FROM 고객 WHERE 나이 IS NULL;
SELECT 고객이름 FROM 고객 WHERE 나이 IS NOT NULL;
정렬 검색
결과 테이블의 내용을 원하는 기준에 따라 정렬하여 출력하는 SELECT 문의 기본 형식은 다음과 같다.
SELECT [ALL : DISTINCT] 속성_리스트 FROM 테이블_리스트 [WHERE 조건] [ORDER BY 속성_리스트 [ASC:DESC]];
오름차순 ASC, 내림차순 DESC (DEFAULT는 오름차순)
ex) SELECT 고객이름, 등급, 나이 FROM 고객 ORDER BY 나이 DESC;
SELECT 주문고객, 주문제품, 수량, 주문일자 FROM 주문 WHERE 수량>=10 ORDER BY 수량 DESC;
집계 함수를 이용한 검색
SUM, AVG 함수는 숫자 데이터 타입의 속성에만 적용할 수 있고, 나머지 함수는 숫자 뿐 아니라 에도 적용할 수 있다.
함수 | 의미 | 사용 가능한 속성의 타입 |
COUNT | 속성 값의 개수 | 모든 데이터(문자와 날짜 데이터 타입의 속성 포함) |
MAX | 속성 값의 최댓값 | |
MIN | 속성 값의 최솟값 | |
SUM | 속성 값의 합계 | 숫자데이터 |
AVG | 속성 값의 평균 |
ex) SELECT AVG(단가) FROM 제품;
SELECT SUM(재고량) AS "재고량 합계" FROM 제품 WHERE 제조업체='한빛제과';
SELECT COUNT(고객아이디) AS 고객수 FROM 고객;
SELECT COUNT(*) AS 고객수 FROM 고객;
SELECT COUNT(DISTINCT 제조업체) AS "제조업체 수" FROM 제품;
그룹별 검색
테이블에서 특정 속성의 값이 같은 투플을 모아 그룹을 만들고, 그룹별로 검색을 하기 위해 GROUP BY 키워드를 사용한다. 그룹에 대한 조건을 추가하려면 GROUP BY 키워드를 HAVING 키워드와 함께 사용하면 된다. GROUP BY 키워드가 없는 SELECT 문은 테이블 전체를 하나의 그룹으로 보고 검색하는 것이다. 그룹별로 검색하는 select 문의 기본 형식은 다음과 같다.
SELECT [ALL : DISTINCT] 속성_리스트 FROM 테이블_리스트 [WHERE 조건]
[GROUP BY 속성_리스트 [HAVING 조건]] [ORDER BY 속성_리스트 [ASC : DESC]];
GROUP BY 키워드와 함께 그룹을 나누는 기준이 되는 속성을 지정한다. 그리고 그룹에 대한 조건은 HAVING 키워드와 함께 작성한다.
ex) SELECT 주문제품, SUM(수량) AS 총주문수량 FROM 주문 GROUP BY 주문제품;
ex) SELECT 제조업체, COUNT(*) AS 제품수, MAX(단가) AS 최고가 FROM 제품 GROUP BY 제조업체;
일반적인 검색 조건은 WHERE 절에 작성하지만 그룹에 대한 조건은 HAVING 절에 작성한다.
ex) SELECT 제조업체, COUNT(*) AS 제품수, MAX(단가) AS 최고가 FROM 제품 GROUP BY 제조업체 HAVING COUNT(*)>=3;
ex) SELECT 등급, COUNT(*) AS 고객수, AVG(적립금) AS 평균적립금 FROM 고객 GROUP BY 등급 HAVING AVG(적립금)>=1000;
ex) SELECT 주문제품, 주문고객, SUM(수량) AS 총주문수량 FROM 주문 GROUP BY 주문제품, 주문고객;
여러 테이블에 대한 조인 검색
여러 개의 테이블을 연결하여 데이터를 검색하는 것을 조인 검색이라 한다. 조인 검색을 하려면 테이블을 연결해주는 속성이 필요하고 이 속성을 조인 속성이라 한다. 테이블을 연결하려면, 조인 속성의 이름은 달라도 되지만 도메인은 반드시 같아야 한다. 일반적으로 테이블의 관계를 나타내는 외래키를 조인 속성으로 이용한다.
ex) SELECT 제품.제품명 FROM 제품, 주문 WHERE 주문.주문고객='banana' AND 제품.제품번호=주문.주문제품;
SELECT 주문.주문제품, 주문.주문일자 FROM 고객, 주문 WHERE 고객.나이>=30 AND 고객.고객아이디=주문.주문고객;
테이블에 별명을 부여할 수 있다.(AS 생략 가능)
SELECT 주문제품, 주문일자 FROM 고객 c, 주문 o WHERE C.나이>=30 AND o.주문고객=c.고객아이디;
부속 질의문을 이용한 검색
SELECT 문 안에 또 다른 SELECT 문을 포함할 수도 있다. 부속 질의문은 괄호로 묶어 작성하고 ORDER BY 절을 사용할 수 없으며, 상위 질의문보다 먼저 수행된다. 부속 질의문을 이용한 검색은 이어 달리기처럼 부속 질의문을 먼저 수행하고, 그 결과를 이용해 상위 질의문을 수행하여 최종 결과 테이블을 반환한다.
ex) 판매 데이터베이스에서 달콤비스킷을 생산한 제조업체가 만든 제품들의 제품명과 단가를 검색하라
SELECT 제품명, 단가 FROM 제품 WHERE 제조업체=(SELECT 제조업체 FROM 제품 WHERE 제품명='달콤비스킷');
ex) 판매 데이터베이스에서 적립금이 가장 많은 고객의 고객이름과 적립금을 검색해보자.
SELECT 고객이름, 적립금 FROM 고객 WHERE 적립금=(SELECT MAX(적립금) FROM 고객);
ex) 판매 데이터베이스에서 banana 고객이 주문한 제품의 제품명과 제조업체를 검색하라
SELECT 제품명, 제조업체 FROM 제품 SELECT 제품명, 제조업체 FROM 제품 WHERE 제품번호 IN (SELECT 주문제품 FROM 주문 WHERE 주문고객='banana');
IN 연산자는 부속 질의문의 결과 값들 중에서 하나라도 일치하는 것이 있으면 검색 조건이 참이 되게 하는 연산자다.
ex) 판매 데이터베이스에서 banana 고객이 주문하지 않은 제품의 제품명과 제조업체를 검색해보자.
SELECT 제품명, 제조업체 FROM 제품 WHERE 제품번호 NOT IN(SELECT 주문제품 FROM 주문 WHERE 주문고객='banana');
ex) 판매 데이터베이스에서 대한식품이 제조한 모든 제품의 단가보다 비싼 제품의 제품명, 단가, 제조업체를 검색하라
SELECT 제품명, 단가, 제조업체 FROM 제품 WHERE 단가>ALL(SELECT 단가 FROM 제품 WHERE 제조업체='대한식품');
ex) 판매 데이터베이스에서 2019년 3월 15일에 제품을 주문한 고객의 고객이름을 검색해보자.
SELECT 고객이름 FROM 고객 WHERE EXISTS(SELECT * FROM 주문 WHERE 주문일자='2019-03-15' AND 주문.주문고객=고객.고객아이디);
ex) 판매 데이터베이스에서 2019년 3월 15일에 제품을 주문하지 않은 고객의 고객이름을 검색해보자
SELECT 고객이름 FROM 고객 WHERE NOT EXISTS(SELECT * FROM 주문 WHERE 주문일자='2019-03-15' AND 주문.주문고객-고객.고객아이디);
데이터의 삽입
데이터 직접 삽입
INSERT INTO 테이블_이름[(속성_리스트)] VALUES(속성값_리스트);
부속 질의문을 이용한 데이터 삽입
INSERT INTO 테이블_이름([속성_리스트)] SELECT 문;
데이터의 수정
UPDATE 테이블_이름 SET 속성_이름=값1, 속성_이름2=값2, ··· [WHERE 조건];
ex) UPDATE 제품 SET 제품명='통큰파이' WHERE 제품번호='p03';
UPDATER 제품 SET 단가=단가*1.1;
UPDATE 주문 SET 수량=5 WHERE 주문고객 IN (SELECT 고객아이디 FROM 고객 WHERE 고객이름='정소화');
데이터의 삭제
DELETE FROM 테이블_이름 [WHERE 조건];
ex) DELETE FROM 주문 WHERE 주문일자='2019-05-22';
DELETE FROM 주문 WHERE 주문고객 IN (SELECT 고객아이디 FROM 고객 WHERE 고객이름='정소화');
DELETE FROM 주문;
뷰
뷰는 다른 테이블을 기반으로 만들어진 가상 테이블이다. 뷰를 가상 테이블이라고 하는 이유는 일반 테이블과 달리 데이터를 실제로 저장하고 있지 않기 때문이다. 물리적으로 존재하면서 실제로 데이터를 저장하는 일반 테이블과 달리, 뷰는 논리적으로만 존재하면서도 일반 테이블과 동일한 방법으로 사용할 수 있어 사용자는 그 차이를 느끼기 어렵다.
뷰는 기본 테이블을 기반으로 만드러지지만 다른 뷰를 기반으로 새로운 뷰를 만들 수도 있다.
뷰의 생성
CREATE VIEW 뷰_이름[(속성_리스트)] AS SELECT 문 [WITH CHECK OPTION];
SELECT문은 ORDER BY를 사용할 수 없다는 점만 제외하면 일반 SELECT문과 동일하다. 속성 리스트를 생략하면 select 절에 나열된 속성 의 이름을 뷰에서도 그대로 사용한다. (집계 함수는 지정해야돼)WITH CHECK OPTION은 생성한 뷰에 삽입이나 수정 연산을 할 때 SELECT 문에서 제시한 뷰의 정의 조건을 위반하면 수행되지 않도록 하는 제약조건을 의미한다.
ex) 고객 테이블에서 등급이 vip인 고객의 고객아이디, 고객이름, 나이로 구성된 뷰를 우수소객이라는 이름으로 생성해
CREATE VIEW 우수고객(고객아이디, 고객이름, 나이) AS SELECT 고객아이디, 고객이름, 나이 FROM 고객 WHERE 등급='vip' WITH CHECK OPTION;
ex) 제품 테이블에서 제조업체별 제품수로 구성된 뷰를 업체별제품수라는 이름으로 생성해보자
CREATE VIEW 업체별제품수(제조업체, 제품수) AS SELECT 제조업체, COUNT(*) FROM 제품 GROUP BY 제조업체 WITH CHECK OPTION;( WITH CHECK OPTION은 GROUP BY절을 포함해서 안돼.)
뷰의 활용
검색 연산은 모든 뷰에 수행할 수 있지만 삽입 수정 삭제 연산은 허용되지 않는 뷰가 있다는 사실도 기억해야 한다.
변경이 불가능한 뷰의 중요한 특징 몇 가지
1. 기본 테이블의 기본키를 구성하는 속성이 포함되어 있지 않은 뷰는 변경할 수 없다.
2. 기본 테이블에 있던 내용이 아니라 집계 함수로 새로 계산된 내용을 포함하고 있는 뷰는 변경할 수 없다.
3. DISTINCT 키워드를 포함하여 정의한 뷰는 변경할 수 없다.
4. GROUP BY 절을 포함하여 정의한 뷰는 변경할 수 없다.
5. 여러 개의 테이블을 조인하여 정의한 뷰는 변경할 수 없는 경우가 많다.
뷰의 대표적인 장점
1. 질의문을 좀 더 쉽게 작성할 수 있다.
2. 데이터의 보안 유지에 도움이 된다.
3. 데이터를 좀 더 편리하게 관리할 수 있다.
뷰의 삭제
DROP VIEW 뷰_이름
삽입 SQL
삽입 SQL의 개념과 특징
지금까지 살펴본 SQL문은 DBMS에 대화식으로 직접 입력하여 수행 결과를 바로 확인할 수 있지만, 응용 프로그램 안에 삽입해 사용할 수도 있다. 프로그래밍 언어로 작성된 응용 프로그램 안에 삽입하여 사용하는 SQL 문을 삽입 SQL이라 한다.
삽입 SQL 문을 사용할 때 특징
1. 삽입 SQL 문은 프로그램 안에서 일반 명령문이 위치할 수 있는 곳이면 어디든 삽입할 수 있다.
2. 프로그램 안의 일반 명령문과 구별하기 위해 삽입 SQL 문 앞에 EXEC SQL을 붙인다.
3. 프로그램에 선언된 일반 변수를 삽입 SQL 문에서 사용할 수 있다. 단, SQL 문에서 일반 변수를 사용할 때는 앞에 콜론(:)을 붙여 테이블 이름이나 속성의 이름과 구분한다.
수행 결과로 여러 개의 행을 반환하는 SELECT 문을 삽입 SQL 문으로 사용하는 경우에는 커서cursor라는 도구가 필요하다.
커서가 필요 없는 삽입 SQL
SQL문을 실행했을 때 특별히 결과 테이블을 반환하지 않는 CREATE TABLE, INSERT, DELETE, UPDATE, 결과로 행 하나만 반환하는 SELECT 문은 커서가 필요 없다.
int main(){
EXEC SQL BEGIN DECLARE SECTION;
char p_no[4], p_name[21];
int price;
EXEC SQL END DECLARE SECTION;
printf("제품번호를 입력하세요 : ");
scanf("%s",p_no);
EXEC SQL SELECT 제품명, 단가 INTO :p_name, :price
FROM 제품
WHERE 제품번호=:p_no;
printf("\n 제품명=%s",p_name);
printf("\n 단가=%d",price);
return 0;
}
삽입 SQL 문에서 사용할 변수는 미리 BEGIN DECLARE SECTION 문장과 END DECLARE SECTION 문장 사이에 선언
삽입 SQL 문에서 사용할 변수 선언의 시작과 끝을 알려주는 BEGIN DECLARE SECTION과 END DECLARE SECTION은 삽입 SQL의 특별한 명령어이므로 EXEC SQL을 붙여준다.
커서가 필요한 삽입 SQL
SELECT 문의 실행 결과로 여러 행이 검색되는 경우에는 한 번에 한 행씩 차례로 접근할 수 있게 해주는 커서가 필요하다. 커서를 사용하기 전에 먼저 커서의 이름과 커서가 필요한 SELECT 문을 선언해야 한다.
DECLARE 명령어를 이용해 커서를 선언하는 삽입 SQL 문의 기본형식은 다음과 같다.
EXEC SQL DECLARE 커서_이름 CURSOR FOR SELECT 문;
프로그램 안에서 커서를 여러 개 사용할 수 있으므로 커서는 다음 예처럼 이름으로 구분한다.
ex) EXEC SQL DECLARE product_cursor CURSOR FOR SELECT 제품명, 단가 FROM 제품;
커서를 선언한 후 SELECT 문을 실행하는 명령이 별도로 필요하다.
EXEC SQL OPEN 커서_이름;
ex) EXEC SQL OPEN product_cursor;
OPEN 명령어를 이용해 SELECT 문이 실행되면 검색된 행들이 반환되고, 커서는 검색된 행들 중에서 첫 번째 행의 바로 앞에 위치한다. 검색된 행들을 차례로 처리하기 위해 커서를 이동시키는 명령어는 FETCH다. 커서를 이동해 처리할 다음 행을 가리키도록 하고, 커서가 가리키는 행으로부터 속성 값들을 가져와 변수에 저장하는 FETCH 문의 기본 형식은 다음과 같다.
EXEC SQL FETCH 커서_이름 INTO 변수_리스트;
c의 경우 FETCH문을 for, while 과 함께 사용한다.
ex) EXEC SQL FETCH product_cursor INTO :p_name, :price;
커서의 사용을 종료하려면 CLOSE 명령어를 사용한다.
EXEC SQL CLOSE 커서_이름;
ex) EXEC SQL CLOSE product_cursor;
'책 > 데이터베이스개론' 카테고리의 다른 글
9. 정규화 (0) | 2020.12.07 |
---|---|
8. 데이터베이스 설계 (5) | 2020.12.06 |
6. 관계 데이터 연산 (0) | 2020.12.04 |
5. 관계 데이터 모델 (0) | 2020.12.04 |
4. 데이터 모델링 (0) | 2020.12.03 |