Learn & Record
[코리아IT아카데미] SQL 문법 MariaDB (서브쿼리, 단일행 서브쿼리, 서브쿼리 중첩, 다중행 서브쿼리, 다중열 서브쿼리, 무결성 관리, NULL 허용, 기본값) 본문
[코리아IT아카데미] SQL 문법 MariaDB (서브쿼리, 단일행 서브쿼리, 서브쿼리 중첩, 다중행 서브쿼리, 다중열 서브쿼리, 무결성 관리, NULL 허용, 기본값)
Walker_ 2024. 2. 7. 13:481. 서브쿼리
- 쿼리문 안에 또 다른 쿼리문이 포함된 구문, 복합적이고 단계적인 질문을 할 때는 여러 개의 쿼리를 중첩해서 사용
- 단일행 서브쿼리(하나의 값만 리턴), 다중행 서브쿼리(여러개의 행을 리턴), 다중행열(여러개의 열 구성, 여러 행 리턴)
2. 단일행 서브쿼리
- DB에서도 복잡한 쿼리를 실행할 수 있으며 그 방법이 바로 서브쿼리
- 서브쿼리는 다른 쿼리문안에 내장되어 있는 SELECT문이며 연속적으로 실행할 쿼리르 하나로 합침
- 이 때 감싸는 쿼리를 외부쿼리라고 하고, 외부쿼리와 구분하고 실행 순서를 명확히 지정하기 위해 서브쿼리를 감쌈
# 최대 인구수를 가진 도시명
SELECT name FROM tCity WHERE popu = (SELECT MAX(popu) from tCity);
# 가장 많은 아이템의 수를 구함
SELECT MAX(num) FROM tItem;
# 최대량인 80개의 상품을 조사
SELECT item FROM tItem WHERE num = 80;
# 두 명령을 하나로 합침 [서브쿼리]
SELECT item FROM titem WHERE num = (SELECT MAX(num) FROM titem);
3. 연습문제 1
# 1. tStaff에서 성취도가 제일 높은 직원을 조사하라
SELECT max(score) FROM tstaff;
SELECT NAME FROM tstaff WHERE score = 98.5;
SELECT NAME FROM tstaff WHERE score = (SELECT MAX(score) FROM tstaff);
# 2. tStaff에서 평균 이상의 월급을 받는 직원 목록을 출력하라
SELECT AVG(salary) FROM tstaff;
SELECT NAME FROM tstaff WHERE 393.5882 <= salary;
SELECT NAME FROM tstaff WHERE (SELECT AVG(salary) FROM tstaff) <= salary;
# 3. tEmployee와 tProject에서 노조 협상건을 맡은 직원의 이름과 월급을 구하라
SELECT employee FROM tproject WHERE project = '노조 협상건';
SELECT salary FROM temployee WHERE NAME = '권성직';
SELECT NAME, salary FROM temployee WHERE NAME = (SELECT employee FROM tproject WHERE project = '노조 협상건');
# 4. tMember에서 나이가 가장 많은 회원의 이름과 주소를 조사하라
SELECT MAX(age) FROM tmember;
SELECT addr FROM tmember WHERE age = 28;
SELECT member, addr FROM tmember where age = (SELECT MAX(age) FROM tmember);
4. 서브쿼리 중첩
- 쿼리 순차적 진행이기에, 더 복잡한 형태의 질문도 가능
# 청바지 배송비가 얼마인지 조사하는 쿼리문 작성
# 먼저 Item 테이블에서 청바지가 어떤 유형의 상품인지 조사
SELECT category FROM titem WHERE item = '청바지';
# 다음은 패션 유형의 배송비를 조사
SELECT delivery FROM tcategory WHERE category = '패션';
# 두 쿼리문 합침. WHERE 절의 '패션' 자리에 상수 대신 '패션'이라는 결과를 만들어 작성
SELECT delivery FROM tcategory WHERE category = (SELECT category FROM titem WHERE item = '청바지');
# 70,000원 상품을 구매한 사람의 나이를 구하는 쿼리문 작성
# 70,000원 상품 조회
SELECT item FROM titem WHERE price = 70000;
# 70,000원 상품을 구매한 사람 조회
SELECT MEMBER FROM torder WHERE item =
(SELECT item FROM titem WHERE price = 70000);
# 70,000원 상품을 구매한 사람의 나이 조회
SELECT age FROM tmember WHERE MEMBER =
(SELECT MEMBER FROM torder WHERE item =
(SELECT item FROM titem WHERE price = 70000));
5. 연습문제 2
# 1. 대추를 구입한 회원의 이름과 이 회원의 예치금을 구하라
SELECT MEMBER FROM torder WHERE item = '대추';
SELECT money, member FROM tmember WHERE MEMBER = '향단';
SELECT MEMBER, money FROM tmember WHERE MEMBER = (SELECT MEMBER FROM torder WHERE item = '대추');
# 2. 춘향이가 구입한 상품의 가격을 조사하라
SELECT item FROM torder WHERE MEMBER = '춘향';
SELECT price FROM titem WHERE item = '청바지';
SELECT price FROM titem WHERE item = (SELECT item FROM torder WHERE MEMBER = '춘향');
# 3. 배송비가 2000원인 상품을 구매한 회원의 주소를 조사하라
SELECT category FROM tcategory WHERE delivery = 2000;
SELECT item FROM titem WHERE category = '패션';
SELECT MEMBER FROM torder WHERE item = '청바지';
SELECT addr FROM tmember WHERE MEMBER = '춘향';
SELECT addr FROM tmember WHERE MEMBER =
(SELECT MEMBER FROM torder WHERE item =
(SELECT item FROM titem WHERE category =
(SELECT category FROM tcategory WHERE delivery = 2000)));
# 4. 배송비가 3000원인 상품을 구매한 회원의 주소 하나를 조사하라
# 값이 1개 초과로 나오는 상황일 때, LIMIT 적용!
SELECT addr FROM tmember WHERE MEMBER =
(SELECT MEMBER FROM torder WHERE item =
(SELECT item FROM titem WHERE category =
(SELECT category FROM tcategory WHERE delivery = 3000) LIMIT 1));
6. 다중행 서브쿼리
- 여러 개의 결과를 리턴하는 다중행 서브쿼리
- 연산자로 비교하려면 조건절의 쿼리문은 반드시 하나의 단일 값을 리턴해야 함.
- 꼭 조사하려면 결과 셋 중 하나의 값만 조사해서 비교하면 됨
SELECT price FROM titem WHERE item =
(SELECT item FROM torder WHERE MEMBER = '향단');
- 구입한 상품 중 하나의 상품만 리턴하면 = 연산자로 비교 가능. 다수의 값을 원한다면 IN 연산자 사용
- IN은 = 과 달리 여러 개의 값과 비교.
SELECT item, price FROM titem WHERE item IN
(SELECT item FROM torder WHERE MEMBER = '향단');
7. 다중열 서브쿼리
- 결과셋의 컬럼이 여러 개이며 한꺼번에 여러 값과 비교.
- 오라클과 마리아디비는 다중열 서브쿼리를 잘 지원하지만 SQL Server는 아직 지원하지않음
- 다중열이면서 다중행인 결과셋을 리턴하면 복수 레코드의 복수 필드를 한꺼번에 비교 가능
SELECT * FROM tstaff WHERE depart = (SELECT depart FROM tstaff WHERE NAME = '윤봉길')
AND gender = (SELECT gender FROM tstaff WHERE NAME = '윤봉길');
# 쿼리 보다 축약
SELECT * FROM tstaff WHERE (depart, gender) =
(SELECT depart, gender FROM tstaff WHERE NAME = '안중근');
# 다중행 다중열
SELECT * FROM tstaff WHERE (depart, salary) IN
(SELECT depart, MAX(salary) FROM tstaff GROUP BY depart);
8. 연습문제 3
1. 판매 데이터베이스에서 달콤비스킷을 생산한제조업체가 만든 제품들의 제품명과 단가를 검색해보자.
SELECT `제품명`, `단가` FROM `제품` WHERE `제조업체` =
(SELECT `제조업체` FROM `제품` WHERE `제품명` = '달콤비스킷');
2. 판매 데이터베이스에서 적립금이 가장 많은 고객의 고객이름과 적립금을 검색해보자.
SELECT `고객이름`, `적립금` FROM `고객` WHERE `적립금` =
(SELECT MAX(`적립금`) FROM `고객`)
# 3. 판매 데이터베이스에서 banana 고객이 주문한 제품의 제품명과 제조업체를 검색해보자
SELECT 제품명, 제조업체 FROM 제품 WHERE 제품번호 IN
(SELECT 주문제품 FROM 주문 WHERE 주문고객 = 'banana');
# 4. 판매 데이터베이스에서 banana 고객이 주문하지않은 제품의 제품명과 제조업체를 검색해보자
SELECT 제품명, 제조업체 FROM 제품 WHERE 제품번호 NOT IN
(SELECT 주문제품 FROM 주문 WHERE 제조업체 = '대한식품');
9. 무결성 관리
- 데이터베이스 또한 결함이 생길 수 있어, 이를 방지하기 위해 최선의 노력을 해야됨
10. NULL 허용
- NULL은 아무것도 입력되어 있지 않은 것이며 알 수 없거나 결정되지 않은 특수한 상태
- 필수 입력 필드는 NULL 허용해서는 안되며, 없어도 괜찮은 옵션 필드는 NULL 허용해도 상관없음
- 필드의 NULL 허용 속성은 테이블을 생성할 때 필드 속성 뒤에 지정
- NULL이라 지정하면 NULL을 허용하지 않는다는 뜻, NOT NULL이라고 적으면 NULL을 허용하지 않는다는 뜻
CREATE TABLE tCity (
name CHAR(10) PRIMARY KEY,
area INT NULL,
popu INT NULL,
metro CHAR(1) NOT NULL,
region CHAR(6) NOT NULL
);
# 다음 두 쿼리문은 정상 실행
INSERT INTO tcity (NAME, popu, metro, region) VALUES ('울산', 114, 'y', '경상');
INSERT INTO tcity (NAME, metro, region) VALUES ('삼척', 'n', '강원');
# 그러나 다음 두 쿼리문은 에러가 남
INSERT INTO tcity (AREA, popu, metro, region) VALUES (456, 123, 'n,','충청');
INSERT INTO tcity (NAME, AREA, popu) VALUES ('의정부', 456, 123);
- NULL 허용 속성을 DBMS 마다 다르기에 항상 NULL, NOT NULL을 명시하는 것이 바람직하다.
CREATE TABLE tNullable (
NAME CHAR(10) NOT NULL,
age INT
);
INSERT INTO tNullable (NAME, age) VALUES ('흥부', 36);
INSERT INTO tNullable (NAME) VALUES ('놀부');
INSERT INTO tNullable (age) VALUES (37);
11. 기본값
- NULL 허용 속성은 데이터베이스 성능을 저해하는 주범 (항상 NULL인지 점검해야 해서 느릴 수 밖에 없음)
- NULL 허용 대신 기본값 DEFAULT을 사용하는 것이 성능상 유리
- 기본값 : 필드값을 지정하지 않을 때 자동으로 입력할 값
CREATE TABLE tCityDefault (
NAME CHAR(10) PRIMARY KEY,
AREA INT NULL,
popu INT NULL,
metro CHAR(1) DEFAULT 'n' NOT NULL,
region CHAR(6) NOT NULL);
INSERT INTO tCityDefault (NAME,AREA, popu, region) VALUES ('진주', 712, 34, '경상');
INSERT INTO tCityDefault (NAME, AREA, popu, metro, region) VALUES ('인천', 1063, 295, 'y', '경기');
# 에러
INSERT INTO tCityDefault VALUES ('강름', 1111, 22, '강원');
#정상 실행
INSERT INTO tCityDefault VALUES ('강름', 1111, 22, DEFAULT, '강원');
# 기본값을 사용할 때, DEFAULT 키워드 사용가능
UPDATE tCityDefault SET metro = DEFAULT WHERE name = '인천';
- 기본값의 유무와 NULL 허용 여부는 완전히 별개의 속성임을 주의.
- UPDATE 명령으로 NULL로 바꿀 수도 있음