📌 목차
1. 20강 행 개수 구하기 - COUNT
집계 함수
COUNT [ALL/DISTINCT] (집합) // 인수로 주어진 집합의 행 개수를 구해 반환
SUM [ALL/DISTINCT] (집합)
AVG [ALL/DISTINCT] (집합)
MIN [ALL/DISTINCT] (집합)
MAX [ALL/DISTINCT] (집합)SQL= 데이터베이스라 불리는 '데이터 집합'을 다루는 언어
집합의 개수, 합계 궁금하다면 SQL이 제공하는 집계함수 사용하여 구하기 가능
SELECT COUNT (*) FROM sample51;
//인수로 지정된 집합 ( 이 경우에는 테이블 전체)
//괄호 안에 지정할 열의 이름을 입력한다집계함수의 특징 : 복수의 값(집합)에서 하나의 값을 계산 (=집계)
| 일반적 함수 | 하나의 행에 하나의 값 |
|---|---|
| 집계함수 | 집합에 하나의 값 |
더보기
mysql> SELECT COUNT(*) FROM sample51;
+----------+
| COUNT(*) |
+----------+
| 5 |
+----------+SELECT COUNT (*) FROM sample51 WHERE name = 'A';
//name 열의 값이 A인 것의 집계
결과
count(*)
2집계함수와 NULL값
COUNT 인수로 열명 지정 가능. *를 인수로 사용할 수 있는 것은 COUNT 함수뿐
집합 안에 NULL이 있을 경우? NULL값을 제외하고 처리함. (무시)
DISTINCT
: 중복된 값을 제거하는 키워드
SELECT [ALL / DISTINCT] name FROM sample51;ALL 미작성시 자동으로 ALL 선택됨 => name열 쫘르륵 나온다.
중복을 제거한 뒤 개수 구하기
SELECT COUNT(ALL name), COUNT(DISTINCT name) FROM sample51;
// ALL, DISTINCT는 인수가 아니므로 콤마 안붙인다. ALL생략가능.
// "를 사용한 수식자체를 인수로 지정가능하다.더보기
mysql> SELECT DISTINCT name FROM sample51;
+------+
| name |
+------+
| A |
| B |
| C |
| NULL |
+------+
mysql> SELECT COUNT(ALL name), COUNT(DISTINCT name) FROM sample51;
+-----------------+----------------------+
| COUNT(ALL name) | COUNT(DISTINCT name) |
+-----------------+----------------------+
| 4 | 3 |
+-----------------+----------------------+21강 COUNT 이외의 집계함수
mysql> SELECT * FROM sample51;
+------+------+----------+
| no | name | quantity |
+------+------+----------+
| 1 | A | 1 |
| 2 | A | 2 |
| 3 | B | 10 |
| 4 | C | 3 |
| 5 | NULL | NULL |
+------+------+----------+SUM으로 합계구하기
mysql> SELECT SUM(quantity) FROM sample51;
+---------------+
| SUM(quantity) |
+---------------+
| 16 |
+---------------+AVG로 평균내기
mysql> SELECT AVG(quantity), SUM(quantity)/COUNT(quantity) FROM sample51;
+---------------+-------------------------------+
| AVG(quantity) | SUM(quantity)/COUNT(quantity) |
+---------------+-------------------------------+
| 4.0000 | 4.0000 |
+---------------+-------------------------------+이때는 NULL의 값을 무시한 상태로 계산한 결과이다.
NULL의 값을 0으로 간주한 후 평균을 내고자한다면 CASE를 사용한다.
mysql> SELECT AVG(CASE WHEN quantity IS NULL THEN 0 ELSE quantity END) AS avgNULLis0 FROM sample51;
+------------+
| avgNULLis0 |
+------------+
| 3.2000 |
+------------+MIN/ MAX로 최솟값, 최댓값 구하기
22강 그룹화 - GROUP BY
그룹화(GROUP BY) -> 집계함수 활용 범위 넓히기 가능
SELECT * FROM 테이블명 GROUP BY 열1, 열2 ...집계함수로 넘겨줄 집합을 그룹으로 나눔
GROUP BY 구에 열 지정하여 그룹화하면 지정된 열의 값이 같은 행이 하나의 그룹으로 묶임
(=DISTINCT와 같이 중복을 제거하는 효과가 있음. )
| GROUP BY | 집계함수와 함께 사용해야만 의미 있음! |
|---|
그룹화된 그룹이 하나의 집합으로서 집계함수의 인수로 넘겨지기 때문이다. (DISTINCT와의 차이점)
예제 5-13 : name열을 그룹화해 계산하기
mysql> SELECT name, COUNT(name), SUM(quantity) FROM sample51 GROUP BY name;
+------+-------------+---------------+
| name | COUNT(name) | SUM(quantity) |
+------+-------------+---------------+
| A | 2 | 3 |
| B | 1 | 10 |
| C | 1 | 3 |
| NULL | 0 | NULL |
+------+-------------+---------------+GROUP BY의 사용 CASE
: 점포 일별 매출 데이터가 중앙 판매 관리시스템에 전송되어 점포별 매출 실적을 집계해 어떤 점포가 매출이 올라가는지, 어떤 상품이 인기가 있는지 등을 분석할 때 사용됨.
점포별, 상품별, 월별, 일별 등 특정 단위로 집계할 때 사용함.
HAVING 구로 조건 지정
집계함수는 WHERE구의 조건식에서는 사용할 수 없음
ex) WHERE COUNT(name)=1 이런거 안돼 xXXX!!!!
내부처리순서
WHERE 구 → GROUP BY 구 → HAVING 구 → SELECT 구 (별명지정)→ ORDER BY 구
HAVING 구
SELECT 명령 중 하나, GROUP BY 구 뒤에 기술함. 조건식이 참인 그룹값만 클라이언트에게 반환함.
결과적으로 검색 시, 2단 구조를 이룸 (WHERE 구, HAVING 구)
예제 5-14 HAVING을 사용해 검색
mysql> SELECT name, COUNT(name) FROM sample51 GROUP BY name HAVING COUNT(name) = 1;
+------+-------------+
| name | COUNT(name) |
+------+-------------+
| B | 1 |
| C | 1 |
+------+-------------+처리순서가 SELECT보다 앞서므로 별명 사용 불가능하다.
GROUP BY에 지정한 열 이외의 열은 집계함수를 사용하지 않은 채 SELECT 구에 지정불가
SELECT 열1, 열2, 열3 FROM 테이블명 GROUP BY 열1; // 열2, 열3 때문에 에러 발생함.위의 코드에서, 열1는 GROUP BY를 통해 지정됨.
그러나 열2, 열3을 SELECT 구에 그대로 작성시 에러 발생 << 열1 그룹에 대해 열2,열3에서 값이 여러개면 반환 못해!
GROUP BY로 그룹화 시 클라이언트로 반환되는 결과 : 그룹 당 하나의 행만 가능
ㄴ이를 위해, 집계함수를 사용해 집합을 하나의 값으로 계산시켜줌
mysql> SELECT MIN(no),name,SUM(quantity) FROM sample51 GROUP BY name;
+---------+------+---------------+
| MIN(no) | name | SUM(quantity) |
+---------+------+---------------+
| 1 | A | 3 |
| 3 | B | 10 |
| 4 | C | 3 |
| 5 | NULL | NULL |
+---------+------+---------------+mysql> SELECT no,quantity From sample51 GROUP BY no, quantity;
// GROUP BY 구에서 지정한 열이라면 SELECT구에서 지정 OK!GROUP BY로 지정을 통한 순서 정렬 불가 (정렬은 항상 ORDER BY구를 통해)
| 구/기능 | WHERE 구 | GROUP BY 구 | HAVING 구 | SELECT 구 | ORDER BY 구 |
|---|---|---|---|---|---|
| 기능 | 행찾기 | 열을 그룹화 | WHERE의 집계함수사용버전 | 행 선택 *선택 시 전체 선택 간주 | 행들 정렬 |
| 같이쓰는거 | 집계함수랑 같이 사용 SUM AVG MIN MAX COUNT | 열명 | ASC (기본값) 오름차순 DESC 내림차순 | ||
| 비고 | DISTINCT랑 유사 | w. GROUP BY |
mysql> SELECT name, COUNT(name), SUM(quantity) FROM sample51 GROUP BY name ORDER BY SUM(quantity) DESC;
+------+-------------+---------------+
| name | COUNT(name) | SUM(quantity) |
+------+-------------+---------------+
| B | 1 | 10 |
| A | 2 | 3 |
| C | 1 | 3 |
| NULL | 0 | NULL |
+------+-------------+---------------+23강 서브쿼리
서브쿼리 : SELECT 명령에 의한 데이터 질의
상부가 아닌 하부의 부수적인 질의
(SELECT 명령)서브쿼리는 WHERE 구에서 주로 사용됨
mysql> DELETE FROM sample54 WHERE a = (SELECT MIN(a) FROM sample54);
ERROR 1093 (HY000): You can't specify target table 'sample54' for update in FROM clause(MySQL에선 안됨)
위의 에러는 데이터를 추가하거나 갱신할 경우 동일한 테이블을 서브쿼리에서 사용할 수 없도록 되어있기 때문.
=> 해결법 : DELETE 명령을 SELECT 명령으로 바꾸면 됨.
DELETE FROM sample54 WHERE a = (SELECT a FROM (SELECT MIN(a) AS a FROM sample54)AS x);
...
mysql> SELECT * FROM sample54;
+------+------+
| no | a |
+------+------+
| 1 | 100 |
| 2 | 900 |
| 4 | 80 |
+------+------+SQL 에는 순차형 언어에서처럼 변수가 존재하지 않으나, 변수를 사용할 수는 있음.
변수 = (SELECT MIN(a) FROM sample54);
DELETE FROM sample54 WHERE a = 변수;
MYSQL 예시
mysql> set @a = SELECT(MIN (a) FROM sample54);
mysql> DELETE FROM Sample54 WHERE a = @a // @a가 변수이다.서브쿼리의 패턴
1) 하나의 값 을 반환하는 패턴 = 스칼라 값, (많이 사용한다.)
2) 복수의 행이 반환되지만, 열은 하나인 패턴
3) 하나의 행이 반환되지만 열이 복수인 패턴
4) 복수의 행, 복수의 열이 반환되는 패턴
=연산자를 사용하여 비교할 경우에는 스칼라 값끼리 비교할 필요가 있다.
스칼라 값을 반환하는 서브쿼리 = 스칼라 서브쿼리
WHERE 구에 스칼라 서브쿼리 사용 가능, 즉 집계함수를 사용해 집계한 결과를 조건식으로 사용 가능하다.
#SELECT 구에서 서브쿼리 사용하기
상부 SELECT구에는 FROM 구가 없음. (MySQL) ,
Oracle같은 전통적인 데이터베이스 제품에는 FROM생략 불가하므로, FROM DUAL로 지정해서 실행한다.
mysql> SELECT
-> (SELECT COUNT(*) FROM sample51) AS sq1,
-> (SELECT COUNT(*) FROM sample54) AS sq2;
+------+------+
| sq1 | sq2 |
+------+------+
| 5 | 3 |
+------+------+UPDATE의 SET구에서 서브쿼리 사용
UPDATE sample54 SET a = (SELECT MAX(a) FROM sample54);
ERROR 1093 (HY000): You can't specify target table 'sample54' for update in FROM clause // 오류발생https://dev.mysql.com/doc/refman/8.4/en/subquery-errors.html
서브쿼리 에러관련 확인
- This error occurs in cases such as the following, which attempts to modify a table and select from the same table in the subquery:
UPDATE t1 SET column2 = (SELECT MAX(column1) FROM t1);즉, 같은테이블을 선택해서 수정해서그런듯?
위의 에러는 데이터를 추가하거나 갱신할 경우 동일한 테이블을 서브쿼리에서 사용할 수 없도록 되어있기 때문.
: MySQL에서만 안되는거
FROM구에서 서브쿼리사용하기
| 구 | SELECT 구 | SET 구 | FROM 구 |
|---|---|---|---|
| 지정 | 스칼라 서브쿼리 | 스칼라값아니어도 ok |
mysql> SELECT * FROM (SELECT * FROM sample54)sq; // sq는 테이블의 별명
+------+------+
| no | a |
+------+------+
| 1 | 100 |
| 2 | 900 |
| 4 | 80 |
//3장내용
// SELECT구에서 열이나 식에 별명 붙일 수 있다. FROM구에서는 테이블/서브쿼리에 별명 가능네스티드 구조(nested), 중첩구조, 내포구조
SELECT명령 안에 SELECT 명령이 들어 있는 듯 보인다.
이러한 구조는 몇단계로든 구성 가능
예제 5-26 Oracle에서 LIMIT 구의 대체 명령
더보기
SELECT * FROM(
SELECT * FROM sample54 ORDER BY a DESC
)sq
WHERE ROWNUM <=2;INSERT명령과 서브쿼리
INSERT 명령
1. VALUES 구의 일부로 서브쿼리 사용 (스칼라값만)
2. VALUES구 대신 SELECT 명령을 사용
mysql> INSERT INTO sample541 VALUES(
-> (SELECT COUNT(*) FROM SAMPLE51),
-> (SELECT COUNT(*) FROM SAMPLE54)
-> );
Query OK, 1 row affected (0.01 sec)
mysql> SELECT * FROM sample541;
+------+------+
| a | b |
+------+------+
| 5 | 3 |
+------+------+
1 row in set (0.00 sec)values 구 대신에 SELECT사용
mysql> INSERT INTO sample541 SELECT 1,2;
Query OK, 1 row affected (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM sample541;
+------+------+
| a | b |
+------+------+
| 5 | 3 |
| 1 | 2 |
+------+------+
2 rows in set (0.00 sec)= INSERT INTO sample541 VALUES(1, 2)
INSERT SELECT명령
SELECT명령의 결과를 모두 INSERT INTO의 테이블로 전부추가결과를 클라이언트로 반환하지 않고, 추가만함. ← 데이터 복사, 이동에 자주 사용
24강 상관 서브쿼리
EXISTS 술어로 상관서브쿼리를 조합시키기
EXISTS : 서브쿼리가 반환하는 결괏값이 존재하는가를 조사 (스칼라외의것도 모두), 참 거짓을 반환한다.
EXISTS (SELECT 명령)mysql> UPDATE sample551 SET a='YES' WHERE EXISTS(SELECT * FROM sample552 WHERE no2 = no);
Query OK, 2 rows affected (0.01 sec)
Rows matched: 2 Changed: 2 Warnings: 0
mysql> SELECT * FROM sample551;
+------+------+
| no | a |
+------+------+
| 1 | NULL |
| 2 | NULL |
| 3 | YES |
| 4 | NULL |
| 5 | YES |
+------+------+
5 rows in set (0.00 sec)EXISTS 술어에서 서브쿼리 지정하면, 행을 반환할 경우(한 행, 여러 행 무관, 존재자체!)에 참을 돌려줌.
부모자식관계
NOT EXISTS
mysql> UPDATE sample551 SET a = 'NO' WHERE NOT EXISTS(SELECT * FROM sample552 WHERE no2 = no);
// sample551.no = sample552.no2 로 써도 작동함
Query OK, 3 rows affected (0.01 sec)
Rows matched: 3 Changed: 3 Warnings: 0
mysql> SELECT * FROM sample551;
+------+------+
| no | a |
+------+------+
| 1 | NO |
| 2 | NO |
| 3 | YES |
| 4 | NO |
| 5 | YES |
+------+------+
5 rows in set (0.00 sec)행이 존재하지 않는 경우, 참으로 반환
상관서브쿼리
중첩구조 SELECT명령에서
UPDATE(부모)
(SELECT ~~) (자식)상관 서브쿼리 : 부모자식 관계를 가지는 것
이때, 23강의 DELETE는 상관 서브쿼리가 아님. 단순한 서브쿼리로, 단독 쿼리로 실행 가능하다. (mysql에서안댐)
상관 서브쿼리에서 부모 명령과 연관되어 처리된다. → 서브쿼리 부분만 따로 떼어내 실행 불가
열에 테이블명 붙이기
sample551.no 가능
만일 샘플의 열이 같다면 혼선 생길 것을 우려해 테이블명.열명을 알려준다. sample551.no = sample552.no2
집합을 비교할 때
=(등호) 사용 불가능.... IN을 사용 시, 집합 안의 값 존재 여부 판별 가능
특정 열의 값이 'n OR n' 라는 조건식을 지정하는 경우 사용
열명 IN (집합)왼쪽에 저장된 값과 같은 값이 집합 안에 존재하면 참 반환
mysql> SELECT * FROM sample551 WHERE no IN (3,5);
+------+------+
| no | a |
+------+------+
| 3 | YES |
| 5 | YES |
+------+------+
2 rows in set (0.00 sec)no이 3, 5인 행 찾기 //
더보기
mysql> SELECT * FROM sample551 WHERE no IN (SELECT no2 FROM sample552);
+------+------+
| no | a |
+------+------+
| 3 | YES |
| 5 | YES |
+------+------+
2 rows in set (0.00 sec)집합부분을 서브쿼리로 지정함. 스칼라서브쿼리 될 필요 없음. //스칼라는 SELECT, SET에서만
NOT IN 은 반대
NULL값이 있을경우
집계함수에서는 무시처리
IN에서는 무시 X, but 비교할 수가 없음... 즉, IS NULL사용해야한다.
NOT IN 사용 시, 집합 안에 NULL 있으면, 왼쪽 값이 집합 안에 포함되어있지않더라도 참 반환 X , 결과 = 불명(KNOWN)
MySQL
조건식 IN사용시 , 왼쪽 값 집합에 포함/미포함 => 참 / NULL 반환
NOT IN, 왼쪽 값 집합에 포함/미포함 => 거짓/NULL 반환, 결국 집합에 NULL 포함되어 있으면 결과값0, 항상 NULL 반환
===========================
'도서 공부(정리) > SQL첫걸음' 카테고리의 다른 글
| <SQL첫걸음> 7장 복수의 테이블다루기 (0) | 2025.04.08 |
|---|---|
| [SQL 첫걸음] 6장 데이터베이스 객체 작성과 삭제 (0) | 2025.04.06 |
| [SQL첫걸음] 4장 데이터의 추가, 삭제, 갱신 (0) | 2025.03.30 |
| [SQL첫걸음 ] 3장 정렬과 연산 (0) | 2025.03.30 |
| [SQL 첫걸음] 2장 테이블에서 데이터 검색 (0) | 2025.03.23 |