자격증/SQLD

[SQL 첫걸음] 23강. 서브쿼리

동호다찌 2022. 4. 4. 09:28
반응형

서브쿼리

서브쿼리는 SELECT 명령으로 괄호로 묶어 지정하는 하부의 부수적인 질의이다. 보통 SQL명령의 WHERE구에 주로 지정된다.

1. DELETE의 WHERE구에서 서브쿼리 사용하기

sample54 테이블에서 a값이 가장 작은 행을 삭제하려한다.
보통 아래와 같은 순서로 진행된다.

SELECT MIN(a)으로 가장 작은 값 검색 → DELETE문으로 해당 행을 삭제

  • 괄호로 서브쿼리를 지정하면 이 SELECT명령과 DELETE명령을 결합시킬 수 있다.
DELETE FROM sample54 WHERE a=(SELECT MIN(a) FROM sample54);

❗ MySQL에서는 데이터를 추가/갱신할 경우 동일한 테이블을 서브쿼리에서 사용할 수 없기 때문에 에러가 발생한다.

아래와 같이 인라인 뷰로 임시 테이블을 만들도록 처리하면 결과를 볼 수 있다.

DELETE FROM sample54 WHERE a=(SELECT a FROM(SELECT MIN(a) AS a FROM sample54) AS x);


2. 스칼라 값

서브쿼리를 사용할 땐 그 SELECT명령이 어떤 값을 반환하는지 주의해야한다.

  • 1행, 1열 패턴(하나의 값)
> SELECT MIN(a) FROM sample54;
// a열에서 가장 적은 수 출력
  • N행, 1열 패턴
SELECT no FROM sample54;
// no값만 출력
  • 1행, N열 패턴
SELECT MIN(a),MAX(no) FROM sample54;
// a열에서 가장 적은수, no열에서 가장 높은 수 출력
  • N행, N열 패턴
SELECT no,a FROM sample54;
열 지정하여 출력

1번 패턴만이 다른 패턴과 다르게 하나의 값을 반환한다.

  • 이렇게 SELECT문이 하나의 값만 반환하는 것을 '스칼라 값을 반환한다'고 한다.
  • 스칼라 서브쿼리는 다음과 같은 특징이 있다.
  • 스칼라 값을 반환하는 서브쿼리는 = 연산자로 비교가 용이하다.
  • 집계함수는 WHERE구에서는 사용할 수 없지만, 스칼라 서브쿼리는 가능하다.

3. SELECT구에서 서브쿼리 사용하기

SELECT (SELECT COUNT(*) FROM sample51) AS sql1,(SELECT COUNT(*) FROM sample54) AS sql2;

SELECT구에서 스칼라 서브쿼리를 사용할 수 있다.

  • 서브쿼리가 아닌 상부의 SELECT명령에는 FROM구가 없는데, 이는 MySQL에서는 FROM구를 생략할 수 있기 때문이다.

4. SET구에서 서브쿼리 사용하기

SET구에서도 서브쿼리를 사용할 수 있다.

mysql > UPDATE sample54 SET a = (SELECT a FROM (SELECT MAX(a) AS a FROM sample54) AS x);

Query OK, 1 row affected (0.00 sec)
Rows matched: 2  Changed: 1  Warnings: 0

mysql > SELECT * FROM sample54;

+------+------+
| no   | a    |
+------+------+
|    1 |  900 |
|    2 |  900 |
+------+------+
2 rows in set (0.00 sec)
  • 열의 값이 전부 a열의 최댓값으로 갱신되었습니다.

5. FROM구에서 서브쿼리 사용하기

  • FROM구에서는 테이블 이외의 것도 지정할 수 있다. 하지만 기본적으로 테이블을 지정하는 만큼 서브쿼리가 꼭 스칼라 값을 반환하지 않아도 된다.
mysql > SELECT * FROM (SELECT * FROM sample54) AS sq;

+------+------+
| no   | a    |
+------+------+
|    1 |  900 |
|    2 |  900 |
+------+------+
2 rows in set (0.00 sec)

위와 같은 형태를 'nasted 구조', '중첩구조' 등으로 부른다.

5-1. 실제 업무에서 FROM 구에 서브쿼리를 지정하여 사용하는 경우

  • Oracle 같은 경우 LIMIT 구 존재하지 않기 때문에 ROWNUM 구로 행 개수를 제한합니다.
  • 그러나 ROWNUM의 경우 WHERE 구로 인해 번호가 할당되는 방식이기 때문에 행 개수가 제한됩니다.
  • 따라서 이를 정렬한 이후에 상위 몇 건을 추출하는 등의 부수 조건을 붙일 수 없습니다.
  • 이럴 때 FROM 구에 서브쿼리를 사용합니다. 방법은 아래와 같습니다.
SELECT * FROM (
    SELECT * FROM sample54 ORDER BY a DESC
) AS sq WHERE ROWNUM <= 2;

Oracle에는 LIMIT구가 없기 때문에 정렬 후 추출할 행을 제한할때 위와 같이 명령한다.


6. INSERT 명령과 서브쿼리

INSERT 명령에도 서브쿼리를 사용할 수 있습니다. 방법은 아래와 같이 두 가지 입니다.

  • VALUES 구의 일부로 서브쿼리를 사용하는 방법
  • VALUES구 대신 SELECT명령을 사용하는 방법

①의 경우 서브쿼리는 스칼라 서브쿼리로 지정해야하며, 자료형도 일치해야 한다.

mysql > INSERT 
          INTO sample541 
        VALUES((SELECT COUNT(*) 
                  FROM sample51), 
               (SELECT COUNT(*) 
                  FROM sample54));

Query OK, 1 row affected (0.00 sec)

mysql > SELECT * FROM sample541;

+------+------+
| a    | b    |
+------+------+
|    5 |    2 |
+------+------+
1 row in set (0.00 sec)```

정수형 a,b열로 이루어진 빈 테이블 sample541에 위와 같이 값을 추가할 수 있다.

②의 경우는 INSERT SELECT라고 불리는 명령이다.

  • SELECT의 결과를 INSERT INTO로 지정한 테이블에 전부 추가하기 때문에 데이터 복사나 이동에 자주 사용된다.
$ mysql > INSERT INTO sample541 SELECT 1, 2;

Query OK, 1 row affected (0.00 sec)
Records: 1  Duplicates: 0  Warnings: 0

$ mysql > SELECT * FROM sample541;

+------+------+
| a    | b    |
+------+------+
|    5 |    2 |
|    1 |    2 |
+------+------+
2 rows in set (0.00 sec)
  • 이때 SELECT 1, 2의 경우 MySQL에서 실행해보면 그 결과가 아래와 같습니다.
mysql > SELECT 1, 2;

+---+---+
| 1 | 2 |
+---+---+
| 1 | 2 |
+---+---+
1 row in set (0.00 sec)
반응형