일반적으로, 데이터를 작업 할 때, 첫 번째 쿼리의 실행 결과를 두 번째 쿼리에 사용 할 필요가 있습니다.
예를 들어, 한 컬럼의 값이 다른 컬럼의 최대 값과 동일한 튜플들을 선택하고자 합니다.
우리는 이것을 간단한 서브쿼리로 수행 할 수 있습니다. :
--> 최대 값을 선택하고, 메인 쿼리는 이 값과 동일한 튜플들을 선택합니다.
감사하게도, SQL은 결합 쿼리들을 위한 강력한 도구를 가지고 있습니다. = subqueries.
한 번 이를 살펴 봅시다!
subquery : (또한 inner 혹은 nested query 로 불립니다.)
SQL query : (main query 혹은 outer query 로 불립니다.)
서브쿼리 는 또다른 SQL 쿼리 입니다.
서브쿼리들은 SELECT
, UPDATE
, INSERT
, and DELETE
문법 내부에서 중첩됩니다.
Subqueries nested in SELECT statement
- SELECT 문법에서 중첩 된 서브쿼리
SELECT
문법에 중첩 된 서브쿼리는 가장 평범한 유형의 서브쿼리입니다.
서브쿼리는 SELECT
절에서 발생할 수 있고, FROM
, WHERE
절 에서도 발생 할 수 있는데,
SELECT
문으로 사용합니다.
밑의 예제를 따라 가 봅시다.
registered_users
테이블은 두 개의 컬럼을 가집니다 : username
, sign_up_date
:
username | sign_up_date |
---|---|
timbrown | 2012-12-04 |
awesometomas | 2014-11-06 |
darlingKate | 2012-12-04 |
frMartin | 2014-07-03 |
우리는 첫 번째로 등록된 유저들을 선택하기 위해 WHERE
절에 중첩된 서브쿼리를 사용 할 겁니다. :
SELECT
username,
sign_up_date
FROM
registered_users
WHERE
sign_up_date = (
SELECT
MIN(sign_up_date)
FROM
registered_users
);
쿼리의 결과는 밑을 따릅니다 :
username | sign_up_date |
---|---|
timbrown | 2012-12-04 |
darlingKate | 2012-12-04 |
위 예제의 서브쿼리는 single-row-subquery 입니다. (단일 줄 서브쿼리)
이 경우, 간단한 SQL 비교 연산자를 사용하기에 안전한데, (=
,>
,<=
, 등등...)
우리의 쿼리가 오직 단 하나의 컬럼에 단 하나의 줄을 반환 하는 것이 확실하기 때문입니다.
만약 우리가 비교 연산자와 함께 서브쿼리를 사용하고, 서브쿼리가 한 줄 초과을 반환한다면, 에러가 납니다.
위의 에러는 당신이 여러 줄을 반환하는 multiple-row subquery(다중 줄 서브쿼리) 를 사용하지 못한다는 의미가 아닙니다.
그저 IN
, ANY
와 같은 다중 줄 비교 연산자를 사용하라는 겁니다.
결과 집합에 새로운 컬럼을 추가하기 위해서
SELECT
문법 내부에 컬럼 중 하나를 선택하는 서브쿼리를 사용 할 수 있습니다.
테이블 registered_users
로 부터 모든 데이터를 선택하고,
밑에 주어진 테이블 users_info
로부터 정보를 조금 더 추가 해 봅시다.
username | name | birth_date |
---|---|---|
awesometomas | Tomas Jones | 1995-10-07 |
timbrown | Tim Brown | 2000-11-04 |
frMartin | Martin Brown | 2002-12-04 |
darlingKate | Kate Brown | 2005-03-03 |
registered_users
테이블에서 모든 정보를 선택하고,
users_info
테이블에서 실제 유저 이름에 대한 알맞는 정보를 추가 합니다. :
SELECT *, (
SELECT
name
FROM
users_info
WHERE
username = registered_users.username
) AS name
FROM
registered_users;
결과는 밑과 같습니다 :
username | sign_up_date | name |
---|---|---|
timbrown | 2012-12-04 | Tim Brown |
awesometomas | 2014-11-06 | Tomas Jones |
darlingKate | 2012-12-04 | Kate Brown |
frMartin | 2014-07-03 | Martin Brown |
우리가 이미 말했듯이, 당신은 FROM
절에서 SELECT
문법의 서브쿼리를 사용할 수 있습니다.
이 경우에서, 파생된 테이블 (서브쿼리로 우리가 얻은 테이블) 은 별칭되었습니다. : AS name
서브쿼리들은 상호 연관 될 수 있습니다.
상호 연관 된 서브쿼리들은 바깥 쿼리(메인 쿼리)의 값을 이용할 수 있습니다.
상호 연관된 서브쿼리의 예제를 살펴 보겠습니다.
여기 테이블 new_orders
에 이러한 컬럼들을 가집니다 :
id INT
product VARCHAR(40)
product_category VARCHAR(40)
quantity INT
unit_price INT
id | product | product_category | quantity | unit_price |
---|---|---|---|---|
1234 | table | furniture | 10 | 15 |
3434 | chair | furniture | 15 | 20 |
4546 | bed | furniture | 12 | 10 |
5467 | candle | decor | 45 | 40 |
3244 | sticker | decor | 40 | 14 |
3456 | frame | decor | 34 | 12 |
우리는 제품 카테고링츼 평균 가격보다 더 작은 unit_pricd
를 가진
모든 제품들을 선택하기 위해 상호 연관된 서브쿼리를 사용 할 수 있습니다. :
SELECT
id,
producct
FROM
new_orders AS newor
WHERE
unit_price < (
SELECT
AVG(unit_price)
FROM
new_orders
WHERE
product_category = newor.product_category
);
쿼리의 결과가 계산되고 있는 동안, 상호 연관된 쿼리는 테이블의 각 줄 마다 실행되므로,
서브쿼리를 가진 계산 쿼리는 거대한 테이블에 대해서는 많은 시간이 걸릴 수 있습니다.
한 줄 마다, WHERE 절 내부의 서브쿼리가 한 번 씩 실행되므로, 연산이 느릴 수도 있다는 의미이다.
Subqueries nested in the UPDATE statement
- UPDATE 문법 내부의 중첩된 서브쿼리
서브쿼리는 UPDATE
문법에서도 사용 될 수 있습니다.
students
테이블을 업데이트 해 봅시다. 이 테이블은 밑의 컬럼을 가집니다.
name VARCHAR(40)
scholarship INT
exams_passed BOOLEAN
name | scholarship | exams_passed |
---|---|---|
Tom Jones | 200 | FALSE |
Tamara Fetch | 400 | FALSE |
Anthony Pots | 300 | FALSE |
SELECT
문법에 서브쿼리를 사용했던 것과 마찬가지로,
UPDATE
문법에도 WHERE
절 내부에 중첩된 서브쿼리를 사용 할 수 있습니다.
우리는 서브쿼리를 지닌 이러한 유형의 쿼리를 exams_passed
를 TRUE
로 설정하기 위해 사용 할 건데,
exam_results
테이블 내부의 두 시험이 둘 다 18점보다 크거나 같다면 TRUE
로 설정합니다.
exam_results
테이블은 밑의 컬럼들을 가지고 있습니다.
name VARCHAR(40)
math_exam_mark INT
english_exam_mark INT
name | math_exam_mark | english_exam_mark |
---|---|---|
Tom Jones | 22 | 23 |
Tamara Fetch | 18 | 15 |
Anthony Pots | 18 | 18 |
students
테이블을 업데이트 하기 위해 밑의 쿼리를 사용합니다 :
UPDATE
students
SET
exams_passed = TRUE
WHERE
name IN (
SELECT
name
FROM
exam_results
WHERE
math_exam_mark >= 18
AND english_exam_mark >= 18
);
name IN ( subqueries )
해당 쿼리는 name 값이 subqueries로 나오는 결과값들 중 하나에 해당된다면
name IN ( ... 의미는 name 은 subquery의 결과 중 하나에 속한다 라는 의미가 됩니다.
위 쿼리 실행 후, 테이블 students
는 밑과 같습니다 :
name | scholarship | exams_passed |
---|---|---|
Tom Jones | 200 | TRUE |
Tamara Fetch | 400 | FALSE |
Anthony Pots | 300 | TRUE |
우리는 서브쿼리를 가진 UPDATE
를 값을 조정하기 위해 사용 할 수도 있습니다.
우리는 밑의 쿼리를 사용할 건데,
시험들을 통과하지 못한 모든 학생들에 대해 최소한의 장학금(scholarship) 으로 설정하기 위해 사용합니다.
scholarships
테이블에 장학금 amount
가 저장되어 있다고 가정하겠습니다.
UPDATE
students
SET
scholarship = (
SELECT
MIN(amoun)
FROM
scholarships
)
WHERE
exams_passed = FALSE;
이제 Tamara Fetch 학생의 장학금은 200과 동일합니다 :
name | scholarship | exams_passed |
---|---|---|
Tom Jones | 200 | TRUE |
Tamara Fetch | 200 | FALSE |
Anthony Pots | 300 | TRUE |
Subqueries nested in the INSERT statement
- INSERT 문법 내부의 중첩된 서브쿼리
INSERT
문법에서,
우리는 서브쿼리에서 반환된 데이터를 다른 테이블에 삽입하기 위해 서브쿼리를 사용 할 수 있습니다.
밑의 예제는 employees
테이블로 작업하게 되며, 이러한 컬럼을 가집니다 :
name VARCHAR(20)
salary INT
department_id INT
name | salary | department_id |
---|---|---|
Ann Reed | 4000 | 1 |
department (부서) 에 대한 모든 데이터는 departments
테이블에 저장되어 있습니다.
id INT
department VARCHAR(20)
id | department |
---|---|
1 | HR |
2 | IT |
3 | PR |
employees
테이블에 Tomas Hedwig 직원에 대한 정보를 추가 해 봅시다.
이 직원은 PR 부서에서 일하며, 연봉은 Ann Reed의 연봉과 동일합니다.
연봉과 부서 ID를 얻기 위해서 우리는 밑에 보여진 서브쿼리들을 사용 할 겁니다 :
INSERT INTO employees
VALUES (
'Tomas Hedwig',
(SELECT salary FROM employees WHERE name = 'Ann Reed'),
(SELECT id FROM departments WHERE department = 'PR')
);
쿼리 실행 이후, employees
테이블은 두 개의 줄을 가지게 됩니다 :
name | salary | department_id |
---|---|---|
Ann Reed | 4000 | 1 |
Tomas Hedwig | 4000 | 3 |
Subqueries nested in the DELETE statement
- DELETE 문법 내부의 중첩된 서브쿼리
우리는 DELETE
문법에서 서브쿼리들을 사용할 수도 있는데,
WHERE
절 내부 조건의 일부로 사용 할 수 있습니다.
두 개의 테이블을 가지고 있다고 가정하겠습니다.
1. 테이블 orders
order_id INT
customer_id INT
product VARCHAR(20)
city VARCHAR(20)
order_id | customer_id | product | city |
---|---|---|---|
1 | 1 | shampoo | London |
2 | 1 | hair mask | London |
3 | 2 | hair mask | London |
2. 테이블 customers
customer_id INT
name VARCHAR(40)
customer_id | name |
---|---|
1 | Ann Smith |
2 | John Doe |
3 | Sam Brown |
우리는 orders
테이블에서 Ann Smith 가 만든 모든 주문들을 삭제 할 겁니다.
DELETE FROM orders
WHERE
customer_id = (SELECT customer_id FROM customers WHERE name = 'Ann Smith')
;
이 쿼리 실행 후, orders
테이블을 밑과 같이 생겼습니다 :
order_id | customer_id | product | city |
---|---|---|---|
3 | 2 | hair mask | London |
UPDATE
때와 마찬가지로, DELETE
문법에서도 쿼리와 서브쿼리에서 동일한 테이블을 사용 할 수 없습니다.
Conclusion - 결론
이번 주제에서는, 서로다른 서브쿼리의 유형에 대해 배워 봤습니다.
이제 당신은 쿼리의 서로 다른 부분에서 서브쿼리를 사용 할 수 있으며,
서로 다른 유형의 구문에서도 서브쿼리를 사용 할 수 있습니다.
이제 연습하러 가 봅시다!
'Hyperskill - 컴퓨터 CS 및 영어 독해 > Introducing to SQL' 카테고리의 다른 글
Set operations - 집합 연산자들 (1) | 2024.05.01 |
---|---|
Consistency constraints - 일관성 제약 조건 (0) | 2024.04.30 |
GROUP BY statement - GROUP BY 문법 (0) | 2024.04.28 |
Aggregate functions - 집계 함수들 (0) | 2024.04.27 |
Inserting selected rows - 선택된 줄 삽입하기 (0) | 2024.04.26 |