Sql

SQL 첫걸음 CH05. 집계와 서브쿼리

hojomu 2023. 3. 15. 11:18
집계함수
COUNT(집합)
SUM(집합)
AVG(집합)
MIN(집합)
MAX(집합)

1 _ 행 개수 구하기 COUNT

 

 - count 예제

sample51

 - sample51의 행의 갯수를 알 수 있다.

 - 명령어가 from -> where -> select 순서로 진행되기 때문에 name이 A인 행 2개를 세었다.

 

** count() 내부에 *(전체) 로 집합을 설정하면, 하나의 행에 NULL이 아닌 열이 하나라도 있으면 모두 센다

 

 - DISTINCT로 중복 제거 

 - 해당 열을 중복값 없이 출력할 수 있다.

 

 - count 내부에 distinct를 넣는 것으로 null 값을 세지 않을 수도 있다.


2 _ COUNT 이외의 집계함수

 : 기본적으로 집계함수에서는 NULL 값을 무시한다 ( 완전히 존재하지 않는 것으로 취급한다 )

만약, NULL에 값을 부여해서 처리하고 싶다면 NULL 값을 특정 값으로 변환해서 집계함수를 사용해야한다.

 

 - 문자열의 경우 A보다 C가 값이 크다.

 


3 _ 그룹화 GROUP BY

 : 집계함수를 사용할 때 값들을 일정한 조건으로 그룹을 만들어서 결과를 보고싶을 때 그룹화를 한다.

SELECT * FROM 테이블명 GROUP BY 열1, 열2 ...

 - name을 기준으로 그룹화를 했기 때문에 name 열 내부에 있던 값들을 기준으로 그룹이 나누어졌다

따라서 중복값 A 를 갖던 quantity 1 과 2는 sum을 통해 3으로 합쳐졌다.

B와 C는 각각 그룹화했지만 값이 1개씩 밖에 없어서 별 다른 변화가 없다.

 

** 내부 처리 순서가 where - group by - select - order by 이기 때문에

그룹화가 필요한 집계함수는 where 구에서 지정할 수 없다.

따라서, 그룹화가 한 집계함수를 지정하고싶으면 HAVING 구를 이용해야한다

where - group by - having - select - order by

 

having을 where처럼 써서 그룹화된 집계함수를 불러왔다.


 - 복수열의 그룹화

 : 위의 코드에서 name열은 그룹화를 했기 때문에, select의 요소로 지정이 가능하지만,

a나 quantity 열 같은 경우는 그룹화가 되어있지 않기 때문에 select의 요소로 지정할 수 없다

( 그룹화 되어있는 행 내부에 a, quantity의 여러 값들이 존재하기 때문에 어떤 값을 불러올지 확정할 수가 없다)

 -> 따라서 집계함수를 써서 값을 지정해줘야한다.

 

 - 결과값 정렬 ( order by )

 


4 _ 서브쿼리

 : 쿼리 안에 또 다른 쿼리를 작성

(SELECT 명령)

-- a열의 최소값인 데이터의 행을 삭제하는 예제

--> mySQL은 해당 명령어를 사용하면, 데이터를 추가하거나 갱신할 때 동이란 테일블을 서브쿼리에서 사용할 수 없도록 에러가 뜨게 만든다. ( 다른 프로그램은 정상 작동 )

이를 방지하기 위해서 다음과 같이 사용해야한다.

 - 이는 sample54 내부의 a열 최소값을 a에 저장시킨 후 해당 테이블을 x로 저장한 후 불러오는 과정이다

( 같은 이름의 테이블에서 데이터를 가지고 올 수 없기 때문에 x라는 테이블을 거쳐서 와야한다. )

 

** 명령문에서 서브쿼리는 항상 먼저 작동한다.

 


서브쿼리의 종류

 : 서브쿼리는 선언된 위치에 따라 명칭이 바뀐다.

 

1) 스칼라

 : select 결과가 하나의 행과 하나의 열로 되어있음.

select (select * from 테이블명)
from 테이블명;

 - sample51 과 54의 행의 갯수를 각각 sq1, sq2로 저장해서 나타내는 모습,

1행에 1열로 된 데이터로서 '스칼라' 라고 부른다.

 

2) 서브쿼리

select *
from 테이블명
where 열명 = (select * from 테이블명)

 - 서브쿼리를 이용해서 update 할 수 있다.

 

3) 인라인뷰

 : as 키워드를 이용하여 가상의 테이블명을 반드시 선언해야한다 

select * from (select * from 테이블명) as 가상테이블명

 

 


5 _ 데이터 베이스 내부에서 변수 선언하기 ( pagination 숫자 처리 )

 : 데이터베이스에서 사용할 수 있는 변수가 있다.

게시판의 경우 게시글이 삭제되기도 하고 생성되기도 하면서 게시글의 총 량이 변하기 때문에

이를 페이징하기 위해서는 고정된 no 숫자로는 불가능하다. 따라서 상황에 따라 변화되고 저장될 수 있는 변수가 필요하다.

-> 해당 select 는 @rownum:=@rownum +1 과 no , a 를 불러오는데,

sample54테이블에서 불러 올 때 @rownum 을 0으로 초기화 하고 불러온다.

따라서 게시글이 삭제되거나 생성되도 @rownum이 새롭게 배정되기 때문에

각 페이지마다 게시글의 수를 조정할 수 있다.

 

** tmp : 임시 테이블 생성 / 생성된 곳에서만 사용이 가능하고 이후에 불러올 수 없다.

 


MySQL에서 @rownum을 사용하여 페이지네이션을 만드는 방법은, SELECT 문에서 LIMIT 및 OFFSET 절을 사용하는 것입니다. 아래는 예시 코드입니다:

lessCopy code
SELECT * FROM 
( SELECT @rownum := @rownum + 1 AS row_number, table_name.* 
FROM table_name, (SELECT @rownum := 0) r ) numbered_rows 
WHERE row_number > {start_index} 
LIMIT {page_size};
 

이 예시에서, table_name을 사용하는 부분을 자신이 사용하는 테이블 이름으로 변경하고, {start_index}를 가져올 첫 번째 행의 인덱스로 대체하고 {page_size}를 한 페이지에 표시할 행 수로 대체합니다. @rownum 변수는 하위 쿼리에서 0으로 초기화된 후, table_name 테이블의 각 행마다 증가합니다.

WHERE 절을 사용하여 row_number로 필터링하여 원하는 페이지 범위에 해당하는 행만 검색할 수 있습니다. LIMIT 절은 반환되는 행 수를 {page_size}로 제한합니다.

예를 들어, 100개의 행이 있는 테이블에서 20-29번째 행을 검색하려면, 인덱스가 0에서 시작하기 때문에 {start_index} = 19를 사용하고, {page_size} = 10을 사용하면 됩니다.

 


6 _ 상관 서브쿼리 Exists

 : select 명령의 값이 존재하는지 확인하는 명령어

EXISTS (SELECT 명령)

sample551
sample552

 - sample552의 no2열에 있는 값이 sample551의 no 열에 존재한다면 해당 행의 a 값을 '있음' 으로 UPDATE 한다.


 - NOT EXISTS 예제

 - sample552의 no2열에 있는 값이 sample551의 no 열에 존재하지 않는다면 해당 행의 a 값을 '없음' 으로 UPDATE 한다.

 


열 명이 동일하다면?

 - sample551과 sample552에서 비교하려고 하는 열의 이름이 no로 동일하다면

where no = no 를 써야하는가?

-> 이 때를 대비해서 다음과 같이 쓸 수 있다.

  - 실제로는 sample551은 no , sample552는 no2로 서로 달라서 문제가 없지만 둘다 no 라고 가정한다면

no 앞에 테이블명을 붙여주는 것으로 둘을 구분할 수 있다.

 


 - IN 연산자

 : 스칼라 값끼리 비교할 때는 = 연산자를 사용하낟. 다만 집합을 비교할 때는 in 연산자를 사용한다.

또한 IN은 OR 연산자를 쉽게 사용할 수 있게 도와준다

IN 연산자
열명 IN(집합)

 - in 연산자는 or을 간단하게 줄여주기도 한다.

 

 - in 연산자 예제 ( 단일행 서브쿼리와 다중행 서브쿼리 비교 )

 - no 의 값을 지정해서 행을 찾으려고 했으나, 서브쿼리 내부에 select된 값이 2개이기 때문에

연산자 = 로는 no에 위치를 찾을 수 없다. ( 단일행 서브쿼리 )

 

따라서 IN 연산자를 이용해서 다중행 서브쿼리를 이용해야한다.

 - in 연산자를 이용해서 no의 위치를 특정하면, 서브쿼리 내부에 지정된 값이 여러개이더라도 no의 위치를

특정할 수 있다. ( 다중행 서브쿼리 )


*** 서브쿼리

1. 스칼라 서브쿼리 : select 뒤에 서브쿼리가 들어감

select (select * from 테이블명)

from 테이블명

where 조건식

 

2. 서브쿼리 : where 절의 열명 뒤에 서브쿼리가 들어감

select *

from 테이블명

where 열명 = (select * from 테이블명)

 

3. 인라인뷰 : from 뒤의 테이블 자리에 서브쿼리가 들어감 ( mySQL : as 키워드를 통해 가상의 테이블명을 꼭 설정해야함 )

select *

from ( select * from 테이블명 ) as 가상의 테이블명

 

*** 다중행 서브쿼리 IN, ANY, ALL

-> IN 과 ANY는 or 의 역할 / ALL 은 and 의 역할

 - any : 집합 안의 값들중 하나라도 조건식에 만족하면 true

(여기서 집합 안의 값은 3, 5 이므로, no >= 3 이기만 해도 조건을 만족하기 때문에 결과값으로 3 이상의 no를 출력했다)

 - all : 집합 안의 값들 모두가 조건식을 만족해야 true

( 집합 안의 값이 3, 5 이므로, no >= 5 를 만족하는 no값만 출력하기 때문에 no=5 가 출력됬다. )