[SQL] 서브쿼리

채록·2021년 3월 19일
0

Database

목록 보기
5/11
post-thumbnail

SQL 문 공부 소감
MySQL켜서 테이블확인하고.. field 확인하고.. 다시 django ORM 켜서 create 해주고 했던게 편했던거 같은데 그냥 터미널 하나 켜서 INSERT INTO 해주는것도 나쁘지않아보인다!! 단지 FK가 물려있다던가 field가 엄청 많다던가 하면 난이도 극악으로 급상승 할것같은 느낌은 온다.


I. 서브쿼리

서브쿼리 ?
SQL 명령문 안에 지정하는 하부 SELECT 명령!



Before) 서브쿼리 사용 전 최솟값 DELETE 하기

# STEP1. 최솟값 확인하기
mysql> SELECT min(quantity) FROM products;
+---------------+
| min(quantity) |
+---------------+
|             3 |
+---------------+
mysql> SELECT * FROM products;
+----+--------+-------+----------+
| id | name   | price | quantity |
+----+--------+-------+----------+
|  1 | book   |  1000 |        3 |
|  2 | pencil |   500 |       10 |
|  3 | cd     |  3000 |      100 |
|  4 | book   |  2000 |        5 |
|  5 | rular  |   800 |       10 |
+----+--------+-------+----------+


# STEP2. 확인한 최솟값을 갖는 열 삭제하기
mysql> DELETE FROM products where quantity=3;
mysql> SELECT * FROM products;
+----+--------+-------+----------+
| id | name   | price | quantity |
+----+--------+-------+----------+
|  2 | pencil |   500 |       10 |
|  3 | cd     |  3000 |      100 |
|  4 | book   |  2000 |        5 |
|  5 | rular  |   800 |       10 |
+----+--------+-------+----------+

After) 서브쿼리 사용해 DELETE 하기

MySQL 전용 에러...!!!
MySQL의 특징으로 데이터를 추가나 갱신할 경우 동일한 테이블로 서브쿼리를 사용할 수 없다!! 그래서 사용하려고 하면 다음처럼 에러가 난다.

mysql> DELETE FROM products WHERE quantity=(SELECT max(quantity) FROM products);
ERROR 1093 (HY000): You can't specify target table 'products' for update in FROM clause

이를 해결해 주기 위해선 서브쿼리의 FROM 구는 임시테이블로 다룰수 있음을 기억하며 아래와 같이 SQL을 변경하면 실행할 수 있음을 참고한다!!

mysql> DELETE FROM products WHERE quantity=(SELECT quantity FROM(SELECT min(quantity) AS quantity FROM products) AS ori_products);
Query OK, 1 row affected (0.00 sec)

mysql> select * from products;
+----+--------+-------+----------+
| id | name   | price | quantity |
+----+--------+-------+----------+
|  2 | pencil |   500 |       10 |
|  3 | cd     |  3000 |      100 |
|  4 | book   |  2000 |        5 |
|  5 | rular  |   800 |       10 |
+----+--------+-------+----------+

🤣 아무도 관심 없겠지만 내가 했던 실수...

최소값의 quantity의 별명을 지정하지 않고 그대로 원래 quantity를 선택해 삭제해서 테이블 다 날라갔다...

mysql> DELETE FROM products WHERE quantity=(SELECT quantity FROM(SELECT min(quantity) FROM products) AS ori_products);
Query OK, 5 rows affected (0.00 sec)
mysql> select * from products;
Empty set (0.00 sec)

그래서 다시 똑같이 만들어줬다!!!



+) 스칼라 값

4가지 형태의 서브쿼리 패턴
1. 하나의 값을 반환하는 패턴

mysql> SELECT MIN(quantity) FROM products;
+---------------+
| MIN(quantity) |
+---------------+
|             1 |
+---------------+
  1. 복수의 행이 반환되지만 열은 하나인 패턴
mysql> SELECT quantity FROM products;
+----------+
| quantity |
+----------+
|        1 |
|       10 |
|      100 |
|        5 |
|       10 |
+----------+
  1. 하나의 행이 반환되지만 열이 복수인 패턴
mysql> SELECT MIN(quantity), MAX(quantity) FROM products;
+---------------+---------------+
| MIN(quantity) | MAX(quantity) |
+---------------+---------------+
|             1 |           100 |
+---------------+---------------+
  1. 복수의 행, 복수의 열이 반환되는 패턴
mysql> SELECT name, quantity FROM products;
+--------+----------+
| name   | quantity |
+--------+----------+
| book   |        1 |
| pencil |       10 |
| cd     |      100 |
| book   |        5 |
| rular  |       10 |
+--------+----------+

그렇다면 여기서 스칼라 값 이란???
=> SELECT 명령이 하나의 값만 반환하는 것을 "스칼라 값을 반환한다" 라고 한다!




II. 상관 서브쿼리

EXISTS (SELECT명령)


1. EXISTS ! 존재하니?

이제껏 봐왔던 EXISTS과 같다 (S가 붙는다는 것! 기억!) 입력한 값이 존재하면 , 존재하지 않다면 거짓을 반환한다.


1) EXISTS 일때 값 변경

  • 두개의 테이블 준비 ! 하려고하는건 practice2에 존재하는 id값은 practice1의 해당하는 id값의 a field에 있다고 update 해주기!
mysql> SELECT * FROM practice1;
+----+------+
| id | a    |
+----+------+
|  1 | NULL |
|  2 | NULL |
|  3 | NULL |
|  4 | NULL |
|  5 | NULL |
+----+------+

mysql> SELECT * FROM practice2;
+----+
| id |
+----+
|  3 |
|  5 |
+----+

1차 실패...

practice1의 id라는 이름과 practice2의 id라는 이름이 같은것이 문제였던듯 하다..

mysql> UPDATE practice1 SET a='있음' WHERE EXISTS(SELECT * FROM practice2 WHERE id=id);
Query OK, 5 rows affected (0.01 sec)
mysql> SELECT * FROM practice1;
+----+--------+
| id | a      |
+----+--------+
|  1 | 있음   |
|  2 | 있음   |
|  3 | 있음   |
|  4 | 있음   |
|  5 | 있음   |
+----+--------+

2차 성공

먼저 practice2의 id를 id2라고 이름지어준다.

mysql> ALTER TABLE practice2 CHANGE id id2 int;
mysql> select * from practice2;
+------+
| id2  |
+------+
|    3 |
|    5 |
+------+

이후 위와 같이 UPDATE를 진행해 주었다.

mysql> UPDATE practice1 SET a='있음' WHERE EXISTS (SELECT * FROM practice2 WHERE id2=id);
Query OK, 2 rows affected (0.00 sec)
Rows matched: 2  Changed: 2  Warnings: 0

mysql> SELECT * FROM practice1;
+----+--------+
| id | a      |
+----+--------+
|  1 | NULL   |
|  2 | NULL   |
|  3 | 있음    |
|  4 | NULL   |
|  5 | 있음    |
+----+--------+

이런식으로 상관 서브쿼리를 통해 특정 값의 존재 조건에 따라 값을 변경하는것이 가능하다!!


2) NOT EXISTS 일때 값 변경

코드는 위와 같다! 단지 EXISTS 대신 NOT EXISTS를 사용한다.

mysql> UPDATE practice1 SET a='없음' WHERE NOT EXISTS (SELECT * FROM practice2 WHERE id2=id);
Query OK, 3 rows affected (0.01 sec)
Rows matched: 3  Changed: 3  Warnings: 0

mysql> SELECT * FROM practice1;
+----+--------+
| id | a      |
+----+--------+
|  1 | 없음    |
|  2 | 없음    |
|  3 | 있음    |
|  4 | 없음    |
|  5 | 있음    |
+----+--------+


2. IN

열명 IN(집합)

IN 을 통해 조건을 걸은 값이 포함된 값에 대해서만 반환이 가능하다


mysql> SELECT * FROM practice1 WHERE id IN (SELECT id2 FROM practice2);
+----+--------+
| id | a      |
+----+--------+
|  3 | 있음    |
|  5 | 있음    |
+----+--------+

IN 에서 NULL 사용하기

NULL도 다룰순 있다!! (아예 NULL을 무시했던 다른 집계함수들과 다름)
BUT IS NULL로 써 사용해야 한다.

주의!!
NOT IN의 경우 집합 안에 NULL값이 있으면 참을 반환하지 않는다. => UNKNOWN으로 된다.

profile
🍎 🍊 🍋 🍏 🍇

0개의 댓글