: SELECT문 안에 또 다른 SELECT문을 포함하는 질의
: 다른 SELECT문 안에 들어 있는 SELECT문
괄호로 묶어서 작성하며, ORDER BY를 사용할 수 없음
하나의 행을 결과로 반환하기도 하고, 하나 이상의 행을 결과로 반환하기도함.
부속 질의문을 먼저 수행하고 그 결과를 바탕으로 상위 질의 문 수행
부속 질의문과 상위 질의문을 연결하는 연산자 필요
=, >, <, >=, <= (단일 행 부속 질의문의 경우 사용 가능)IN, NOT IN: 부속 질의문의 결과값 중 일치하는 것의 존재 여부에 따라 검색조건 참/거짓 반환.EXISTS, NOT EXISTS: 부속 질의문의 결과 값이 하나라도 존재하는지의 여부에 따라 검색조건 참/거짓 반환ALL: 부속 질의문읠 결과값 모두와 비교해 결과가 참일 때ANY 또는 SOME: 부속 질의문의 결과값 중 하나라도 비교해 결과가 참일 때.ALL, ANY, SOME은 비교연산자와 함께 사용)예) 대한미디어에서 출판한 도서를 구매한 고객의 이름 나타내기
SELECT name
FROM customers
WHERE custid IN (
SELECT custid
FROM orders
WHERE bookid IN (
SELECT bookid
FROM books
WHERE publisher = '대한미디어')));
서브쿼리를 사용해도 좋지만 JOIN을 사용하여서도 같은 결과를 낼 수 있다.
아래는 (INNER) JOIN을 사용해 같은
SELECT C.name
FROM customers AS C
JOIN orders AS O ON C.custid = O.custid)
JOIN books AS B ON O.bookid = B.bookid
WHERE B.publisher = '대한미디어';
예) 출판사별로 출판사의 평균 도서 가격보다 비싼 도서 구하기
SELECT bookname
FROM books B1
WHERE B1.price > (
SELECT avg(price)
FROM books B2
WHERE B1.publisher = B2.publisher));
위의 코드를 살펴보면 같은 테이블인 books를 B1, B2로 별칭을 각각 설정해주고 있는데 이는 상위 쿼리와 하위 쿼리가 독립적이지 않아서이다.
상위 쿼리에서 행을 하나씩 가져와 하위 쿼리에서 반복하며 상위 쿼리 행의 책의 출판사의 책들의 값의 평균을 구해주면 그것과 상위 쿼리 행의 값을 비교하는 식으로 돌아가기에, 하위 쿼리에서 상위 쿼리의 내용을 가져와야하는데 이때 구분을 위해서 필요하다.
반복문이 아닌데 반복문을 실행하는 것처럼 상위 쿼리의 한 행마다 이제 하위 쿼리가 실행된다는 부분이 처음에는 잘 받아들여지지 않았는데 직접 쳐보니 조금 더 와닿는다.
위의 코드도 JOIN을 쓰는 식으로 수정해보면 아래와같다.
SELECT bookname
FROM books B1
JOIN (SELECT publisher, AVG(price) AS price
FROM books
GROUP BY publisher) B2
ON B1.publisher = B2.publisher
WHERE B1.price > B2.price;
UNION ALL은 중복을 포함하여 모든 결과를 구함예) Customer 테이블에 대한민국에 거주하는 고객의 이름 집합과 도서를 주문한 고객의 이름 집합의 합집합 구하기
SELECT name
FROM customers
WHERE address LIKE '%대한민국%'
UNION
SELECT customers.name
FROM customers
JOIN orders
ON customers.custid = orders.custid;
예) 대한민국에 거주하는 고객의 이름에서 도서를 주문한 고객의 이름을 제외하고 나타내기
SELECT C.name
FROM customers AS C
WHERE C.address LIKE '%대한민국%' AND
C.custid NOT IN (
SELECT custid
FROM orders);
예) 주문이 있는 고객의 이름과 주소를 나타내기
SELECT name, address
FROM customers C
WHERE EXIST (
SELECT custid
FROM orders O
ON C.custid = O.custid));
테이블을 생성하며, 속성과 속성에 관한 제약을 정의한다.
기본키 및 외래키를 정의하는 명령어이다.
CREATE TABLE 테이블 이름 (
<속성명> <데이터 타입> <제약...>
PRIMARY KEY(속성명 )
FOREIGN KEY (속성명 )
);
ON DELETE CASCADE: 관련 튜플을 함께 삭제
ON DELETE SET NULL: 관련 튜플의 외래키 값을 NULL로 변경
ON DELETE RESTRICT: 부모행이 참조되고 있으면 삭제/수정 불가 (기본값)
ON DELETE NO ACTION: SQL 표준 키워드로 RESTRICT와 동일.
예)
CREATE TABLE post (
post_id INT NOT NULL AUTO_INCREMENT,
board_id INT NOT NULL,
content TEXT,
createdAt DATETIME NOT NULL,
PRIMARY KEY(post_id),
FOREIGN KEY(board_id) REFERENCES board ON DELETE CASCADE
);
: 생성된 테이블의 속성 변경 및 속성에 관한 제약 변경 또는 기본키 및 외래키를 변경
ALTER TABLE <테이블명>
ADD <속성이름> <데이터타입>
DROP COLUMN <속성이름>
ALTER COLUMN <속성이름> <데이터타입>
ADD PRIMARY KEY(속성이름 )
ALTER TABLE post
ADD updatedAt DATETIME
DROP COLUMN createdAt;
: 테이블을 삭제하는 명령. 테이블의 구조와 데이터를 모두 삭제함.
데이터만 삭제하려고 할 때는 DELETE를 사용하며, 삭제할 테이블을 참조하는 테이블이 있을 때에는 삭제가 수행되지 않음.
위의 경우
를 통해 테이블을 삭제할 수 있다.
DROP TABLE <테이블 이름>
: 테이블에 새로운 튜플을 삽입하는 명령어
INSERT INTO <테이블 이름> (속성 리스트 )
VALUES (값 리스트 )
속성 리스트를 작성한 순서대로(일대일대응) 값 리스트를 작성해줘야함
속성리스트는 생략 가능하지만, 테이블 정의 시 지정한 속성의 순서대로 값이 삽입되기에 주의해야함.
SELECT 문을 사용해서도 작성할 수 있는데 이 경우는 다른 테이블의 값을 긁어와 넣는 식.
예)
INSERT INTO post (post_id, board_id, content, createdAt)
VALUES (1, 4, '글입니다.', '2026-03-27 16:00:10');
---생략한 속성들에는 NULL 또는 DEFAULT로 설정한 값 입력.
INSERT INTO post (post_id, board_id)
VALUES (5, 3);
: 특정 속성값을 수정하는 명령으로 다른 테이블의 속성값을 이용할 수 있음.
UPDATE <테이블 이름>
SET 속성이름 = 값
WHERE 조건
WHERE 절은 생략 가능하지만, 이 경우 테이블에 존재하는 모든 튜플을 수정하게된다.
예)
UPDATE post
SET content = "ringing siren"
WHERE post_id = 5;
: 테이블에 있는 기존 튜플을 삭제하는 명령
DELETE FROM <테이블 이름>
WHERE 조건
UPDATE문과 동일하게 WHERE 절은 생략 가능하지만, 이 경우에는 테이블에 존재하는 모든 튜플을 삭제하게 된다.