본문 바로가기
SQL

집계와 서브쿼리

by csue 2021. 4. 27.

집계함수

일반적인 함수는 인수로 하나의 값을 지정하는데 집계함수는 함수의 인자로 집합을 지정한다.

COUNT

인수로 주어진 집합의 개수를 구해 반환하는 함수로, 테이블의 행의 개수를 구할 수 있다.

 

ignore NULL

집합 안에 NULL 값이 있을 경우 무시한다.

 

조건식 WHERE

WHERE을 이용하여 조건을 지정할 수도 있다.
SELECT 구와 함께 사용하므로 alias 또한 가능하다.
위에서 생략된 city = NULL 값의 개수를 count 하며, 테이블 이름을 지정해보자.

 

중복제거 DISTINCT

SELECT + DISTINCT

SELECT + COUNT + DISTINCT = COUNT 때문에 NULL 값이 생략된다.

 

SUM

집합의 합계를 구하는 집계함수이다. 수치형만 가능하며, COUNT 와 마찬가지로 NULL 값은 무시한다.

AVG

집합의 평균을 구하는 집계함수이다. SUM 과 마찬가지로 수치형만 가능하고, NULL 값은 무시한다.

MIN / MAX

최소/최대값을 구하는 집계함수이다. 문자열형과 날짜형, 시간형에도 사용 가능하며 NULL 값은 무시한다. 문자열의 경우 사전에 등재되어있는 순서대로 최소/최대값이 결정된다.

GROUP BY

GROUP BY 는 집계함수로 넘겨줄 집합을 그룹으로 나누기 위해 사용되는 구이다. DISTINCT 와 마찬가지로 중복을 제거하는 효과가 있다.

 

조건식 HAVING

집계함수는 WHERE 구에서 사용할 수 없으므로 HAVING 을 사용하여 조건식을 지정한다.

// WHERE 을 사용할 수 없는 이유는 연산의 우선 순위 때문이다
// alias 또한 지정 할 수 없다.
WHERE => GROUP BY => SELECT => ORDER BY

 

정렬 ORDER BY

서브쿼리

서브쿼리란 명령에 의한 데이터 질의로, 하부의 부수적인 질의를 의미한다. 쉽게 말하자면 하나의 쿼리문 안에 있는 또 다른 쿼리이다. 괄호로 묶어 지정한다.

how to use

UPDATE

테스트하던 도중에 id 5~7 의 city 값이 변경되어 아래의 모습과 같아졌다.

 

 

여기에서 city='LoL' 인 행의 city 값을 'delete' 로 UPDATE 해보자.
보통의 서브쿼리 사용문은 아래와 같으나,

// UPDATE 테이블명 SET=WHERE=(변수)
UPDATE users
SET city='delete'
WHERE city=(SELECT city='LoL' FROM users

mysql 의 경우 데이터를 추가하거나 갱신할 때에 동일한 테이블을 서브쿼리에서 사용할 수 없게 되어있으므로 한번 더 감싸서 alias 를 지정해주어야 한다.

mysql> UPDATE users
    -> SET city = 'delete'
    -> WHERE city=(SELECT city FROM
    -> (SELECT city WHERE city='LoL')
    -> AS x);

 

DELETE

이번에는 위에서 UPDATE 해주었던 city='delete' 인 값들을 삭제해보자.
UPDATE 와 같은 방법으로 진행하면 된다.

 

스칼라 값

SELECT 명령이 하나의 값만 반환하는 것을 '스칼라 값을 반환한다' 고 하고, 스칼라값을 반환하는 서브쿼리는 '스칼라 서브쿼리' 라고 한다. 앞서 HAVING 구를 설명할때 집계함수는 WHERE 구에서 사용할 수 없다고 한 바 있다. 그러나 스칼라 서브쿼리라면 WHERE 구에 사용할 수 있으므로 집계함수를 사용해 집계한 결과를 조건식으로 사용할 수 있게 된다.

// 스칼라 서브쿼리의 기본 사용 방법

mysql> SELECT
    -> (SELECT COUNT(*) FROM users) AS COUNT_USER;

+------------+
| COUNT_USER |
+------------+
|          4 |
+------------+
1 row in set (0.00 sec)

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

UPDATESET 에서도 서브쿼리를 사용할 수 있다.
age 의 모든 열의 값을 age 의 최대값으로 갱신해보자.

mysql> UPDATE users
    -> SET age = (SELECT age FROM
    -> (SELECT MAX(age) AS age FROM users) AS x);
Query OK, 3 rows affected (0.00 sec)
Rows matched: 4  Changed: 3  Warnings: 0

mysql> SELECT * from users;
+----+-------+-----+--------+
| id | name  | age | city   |
+----+-------+-----+--------+
|  1 | keria |  26 | 부산   |
|  2 | cuzz  |  26 | 구미   |
|  3 | faker |  26 | 서울   |
|  4 | teddy |  26 | 안양   |
+----+-------+-----+--------+
4 rows in set (0.00 sec)

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

SELECT 명령 안에 SELECT 명령이 들어있는 듯 보이는 구조로, 중첩구조(nested) 혹은 내포구조 라고 부른다.

mysql> SELECT * FROM (SELECT * FROM users) AS new;
+----+-------+-----+--------+
| id | name  | age | city   |
+----+-------+-----+--------+
|  1 | keria |  26 | 부산   |
|  2 | cuzz  |  26 | 구미   |
|  3 | faker |  26 | 서울   |
|  4 | teddy |  26 | 안양   |
+----+-------+-----+--------+
4 rows in set (0.00 sec)

INSERT 명령과 서브쿼리

서브쿼리를 사용하면 INSERT 에서 VALUES 의 일부로 서브쿼리를 사용하는 방법과, VALUES 를 대신하여 SELECT 명령을 사용하는 두 가지 방법이 있다.

서브쿼리를 사용하는 방법

mysql> INSERT INTO nums VALUES(8,
    -> (SELECT COUNT(no) FROM nums AS a),
    -> (SELECT COUNT(price) FROM nums AS b),
    -> (SELECT COUNT(quantity) FROM nums AS c));
Query OK, 1 row affected (0.00 sec)

// 같은 테이블 내에서 지정하는 경우 alias 를 붙여주지 않으면 specify target error 발생

mysql> SELECT * from nums;
+----+----+-------+----------+
| id | no | price | quantity |
+----+----+-------+----------+
|  1 |  1 |    10 |        1 |
|  2 |  1 |    10 |        2 |
|  3 |  1 |    10 |        3 |
|  4 |  2 |    17 |       10 |
|  5 |  2 |    17 |       17 |
|  6 |  2 |   100 |        4 |
|  7 |  3 |   517 |       93 |
|  8 |  7 |     7 |        7 | // 8번째 행이 추가되었다.
+----+----+-------+----------+
8 rows in set (0.00 sec)

SELECT 를 사용하는 방법

mysql> INSERT INTO nums SELECT 9, 9, 9, 9;
Query OK, 1 row affected (0.00 sec)
Records: 1  Duplicates: 0  Warnings: 0

// SELECT가 결과값으로 9, 9, 9, 9 라는 상수를 반환하므로,
// INSERT INTO nums VALUES (9,9,9,9)와 같은 결과를 불러온다. 

mysql> SELECT * from nums;
+----+----+-------+----------+
| id | no | price | quantity |
+----+----+-------+----------+
|  1 |  1 |    10 |        1 |
|  2 |  1 |    10 |        2 |
|  3 |  1 |    10 |        3 |
|  4 |  2 |    17 |       10 |
|  5 |  2 |    17 |       17 |
|  6 |  2 |   100 |        4 |
|  7 |  3 |   517 |       93 |
|  8 |  7 |     7 |        7 |
|  9 |  9 |     9 |        9 | // 9번째 행이 추가되었다.
+----+----+-------+----------+
9 rows in set (0.00 sec)

nums 와 nums1 의 열 구성이 같다고 가정할때, 아래와 같은 방법으로 nums1 의 행을 복사해올수도 있다.

INSERT INTO nums SELECT * FROM nums1;

상관 서브쿼리

상관 서브쿼리란 부모 명령과 자식인 서브쿼리가 서로 연관되는 경우를 의미한다. 상관 서브쿼리를 사용함으로써 두 테이블에 걸쳐 조작할 수 있다.

EXISTS 술어를 이용하여 서브쿼리가 반환하는 결과값이 있는지 확인할 수 있다.
EXISTS 를 사용하는 경우, 서브쿼리가 반환하는 결과값이 있는지를 확인하여 있으면 참 없으면 거짓을 반환하기 때문에 서브쿼리가 스칼라값을 반환하지 않아도 된다.

'SQL' 카테고리의 다른 글

db index & view  (0) 2021.04.27
데이터베이스 객체의 생성과 삭제  (0) 2021.04.27
데이터 추가 / 삭제 / 갱신  (0) 2021.04.27
데이터 검색 / 정렬 / 연산  (0) 2021.04.27
DBMS  (0) 2021.04.27