[Day 8] 데이터 분석을 위한 SQL 기초

임종우·2022년 9월 23일
0

ai_school_TIL

목록 보기
5/34

매주 금요일은 special Lecture 시간이다. 당분간은 SQL에 대해 배운다!
오늘 SQL 강의의 첫 시간이었는데, 재밌게 들었다.
정석적인 이론보다는, 실무에서 사용할 수 있는 능력을 갖추도록 해주는 강의 같다.
강의를 통해 SQL의 기초를 다지고, 스스로 여러 문제를 풀어보며 감을 익혀, 실무에서 SQL을 언제든 사용할 수 있게 만들자!


Database

Database란?

데이터베이스란, 데이터를 저장하고 관리할 수 있게 해주는 시스템과 그 안에 저장된 데이터 를 말한다.
이때, 데이터를 관리하는 프로그램을 DBMS(DataBase Management System)이라고도 부르는데, 우리가 흔히 말하는 데이터베이스 제품이 바로 DBSM이다. 강의에서 우리는 MYSQL을 사용했다!

Database의 종류

  1. 관계형 데이터베이스
    2차원 표 형식으로 데이터를 관리하는 데이터베이스로, 현재 가장 주류를 이루고 있는 형태이다. 보통의 데이터베이스라 하면 바로 이 관계형 데이터베이스를 말한다. 이를 RDB(Realation DataBase) 혹은 RDBMS라고도 하며, ORACLE, MYSQL, PostgreSQL 등이 있다.

  2. NoSQL 데이터베이스
    Not Only SQL Database의 약자이다. 여기서 SQL(Structured Query Language)이라고 함은, 관계형 데이터베이스에서 사용하는 언어를 의미한다!
    기존의 관계형 데이터베이스 보다 더 융통성 있는 데이터 모델을 사용하고, 데이터의 저장 및 검색을 위한 특화된 매커니즘을 제공한다.
    대량 데이터의 동시 및 고속 처리를 위해 사용한다. acebook, Twitter, Netflix, Instagram, Apple의 iCloud, 삼성의 SCloud 등이 그 예시이다. redis, MongoDB, cassandra 등이 있다.

  3. 계층형 데이터베이스
    데이터를 계층 구조로 관리하는 데이터 베이스

이 외에도 몇 가지의 종류가 있지만, 대부분의 데이터베이스는 관계형 데이터베이스이며, 요즘은 NoSQL 데이터베이스의 사용도 조금 늘어난 상황이라고 한다.

Database의 주요 기능

  1. 데이터의 검색 및 갱신
    1.1 데이터의 검색(SELECT), 추출 또는 질의
    데이터베이스에 있는 데이터를 검색하여 추출한다. 이때, 원본 데이터 자체를 변형시키지 않는다.
    1.2 데이터의 갱신
    UPDATE (SET), DELETE FROM, INSERT INTO 등 의 기능으로 기존 데이터를 수정하고, 데이터를 삭제하거나, 새로운 데이터를 등록한다.
  1. 동시성 제어
    데이터베이스에는 많은 사용자가 동시에 접근하기 때문에 동시성 제어 기능이 필요하다.
    예를 들어 A가 하나의 데이터에 접근해 수정하고 있을때, B 역시 그 데이터를 수정하려한다면?
    1 : B는 파일을 열 수 없다. 2 : B는 파일을 볼 수만 있다. 3 : A와 B가 동시에 수정할 수 있다.
    라는 세 가지의 선택지로 동시성 제어를 할 수 있다. 이때, 3번째 선택지는 dirty write라고 부른다.

  2. 장애 대응
    데이터가 손실되는 경우를 대비해 데이터를 여러 곳에 분산해서 저장하는 등의 방법으로 데이터를 보호하며, 장애에 대응한다.

  3. 보안
    데이터베이스의 보존된 데이터가 외부로 유출되지 않도록 보안 기능이 필요하다.

이상 네 가지가 데이터 베이스가 가지고 있는 주요 기능이다. 우리는, 데이터 분석의 측면에서 SQL과 데이터베이스를 활용하고자 하고 있으므로, 여기서 데이터의 검색에 집중한다.


SQL

그럼 이제 SQL의 기초적인 문법 및 사용법에 대해 알아보자.

일단, SQL이 관계형 데이터베이스의 언어인 만큼, SQL에서 다루는 데이터들은 2차원의 표로 이루어져 있으며, 행과 열이 존재한다.
따라서 우리가 데이터라고 말하면 행 하나를 의미한다고 생각할 수 있다.

그리고, SQL의 문법에서는 줄 바꿈이나 띄어쓰기에 큰 의미가 없다. 그저 가독성을 좋게 하기 위해서 사용한다.
또한, 문자열을 제외하고는 대소문자를 구분하지 않는다. 그러나 가독성을 위해 예약어는 대문자로, 나머지는 소문자로 사용한다.

오늘 학습한 SQL의 기본 문법은 다음과 같다.

SELECT

FROM

WHERE

GROUP BY

HAVING

ORDER BY

LIMIT

사용 순서도 위와 같다.

SELECT, FROM

가장 기본적인 기능은 SELECT와 FROM이다. 우리가 SQL을 사용하는 이유인 데이터의 검색(질의)를 하는데 사용된다.
SELECT를 통해 테이블에서 가져올 데이터의 column을 선택하고, FROM을 통해 어떤 테이블에서 자료를 가져올 지 선택한다.
이때, SELECT *은 모든 column을 표시할 것임을 의미한다.

SELECT  *   		-- 모든 컬럼을 선택  (--는 주석처리 의미)
FROM  station 		-- station이라는 테이블에서 데이터를 가져오겠다.
LIMIT  10 			-- 10개만 출력

위와 같이 사용할 수 있다.
이때, LIMIT는 데이터의 개수를 의미한다. LIMIT 10을 통해 상위 10개의 데이터만 출력할 것임을 의미한다.

일부 열만 가져오기 위해서는 다음과 같이 사용한다.

SELECT name
      , address  		-- name과 address column 만 가져온다.
FROM  station			-- station이라는 테이블에서 데이터를 가져오겠다.
LIMIT  10 				-- 10개만 출력

SQL에서 --는 주석의 의미이다.
위의 코드를 보면, SELECT 절을 각 column에 대해 두 line으로 나누어 작성했는데, 가독성과 주석 처리를 쉽게 하기 위해 저런 방식으로 사용하기도 한다.

SELECT 절 내에서 사용하는 다양한 함수

SELECT 절을 이용해 데이터를 추출할 때, 다양한 집계함수를 사용하여 집계 결과를 얻어낼 수 있다.

  1. count() : count 함수를 사용할 수 있다.
SELECT COUNT(*)
FROM tips

위와 같이 사용하면, tips table에 있는 데이터의 개수를 파악한다.

SELECT count(DISTINCT day)
FROM tips

위와 같이 DISTINCT 와 함께 사용하면, 고유 값들의 개수만 세줄 수 도 있다.

  1. sum()
SELECT SUM(total_bill)
FROM tips

위와 같이 사용하여, 특정 column의 합을 구할 수도 있다.

  1. avg()
SELECT AVG(total_bill)
FROM tips

평균을 구하기 위해서는 avg() 함수를 사용한다.

  1. max(), min()

    SELECT MIN(total_bill), MAX(total_bill)
    FROM tips
    

    최댓값과 최솟값 역시 구할 수 있다.

다음의 예시를 보자.

SELECT min(age) as min_age
     , max(age) as max_age
     , max(age)-min(age) as age_diff
From records

위 예시는, records 테이블에서 age column의 값을 다양한 집계함수를 이용해 계산하고, 계산 결과를 as를 이용해 새로운 컬럼의 이름을 정해주어 출력하는 예시이다. 위와 같은 방법으로도 집계함수를 활용할 수 있다.

집계함수들을 사용할 때, 주의해야 할 점이 있다. 바로 NULL값을 진짜 NULL으로, 없는 값으로 칠 것이냐 혹은 0으로 생각하고 사용할 것이냐 의 문제이다. 예를 들어, 평균을 구할 때 결측치가 있는 값들을 제외하고 구한다면, 나머지 값들의 합을 개수로 나누어주면 되지만, 결측치가 있는 값을 포함하고 구하고 싶다면, 나머지 값들의 합을 전체 데이터의 개수로 나누어야 한다.

그렇게 NULL 값을 어떻게 처리할 것인지 결정하는 것에 따라 사용할 집계 함수가 달라진다.
집계함수를 사용할 때, COUNT(*)과 같이 전체 열에 대해 집계함수를 사용한다면, NULL 값이 있는 데이터도, 해당 행의 모든 값이 NULL이 아니라면 포함하여 세게 된다. 반면 COUNT(NULL이 있는 column)과 같이 사용한다면, NULL 값은 제외하고 개수를 센 결과를 반환한다.
그래서 NULL값을 NULL로 보고 제외한 채 평균을 구하고 싶다면, AVG(column)과 같이 사용하면 되나, 0으로 보고 포함하여 평균을 구하고 싶다면 SUM(column)/COUNT(*) 과 같은 방법을 이용하여 구해야 한다.

WHERE

WHERE는 테이블에서 특정 조건만 만족하는 데이터를 가지고 오기 위해 사용한다.
WHERE column 조건 등과 같이 사용할 수 있다.

SELECT *
FROM  station
WHERE local = '마포구' 		
LIMIT 10

해당 코드는, station table에서 local이 '마포구'인 데이터만 뽑아온다.
이때, 비교를 위한 연산자로는 =, >, <, >=, <=, <>, !=를 사용할 수 있다.

이 때, 특정 column 등에 별칭을 붙여 사용할 수도 있다.
AS (Alias)를 사용하며, 이는 생략 가능하지만, 가독성을 위해 생략하지 않는 것을 추천한다.

SELECT name AS staion_name
	 , address AS station_address
FROM  station
WHERE local = '마포구'
LIMIT 10

위와 같이 작성하면 출력 결과의 column으로는 station_name과 station_address가 존재하게 된다.

WHERE를 사용해 조건을 걸어 특정 데이터들만 가져올 때, ANDOR를 사용하여 여러 조건을 사용한다.

SELECT *
FROM  station
WHERE local = '마포구' 
OR local = "광진구"

이 때 중요한 점은, AND나 OR로 연결되는 조건들은 각각 완결된 조건이어야 한다는 점이다.
다시 말하자면, 다음과 같이 쓸 수 없다.

SELECT *
FROM  station
WHERE local = '마포구' or '광진구'

자주 실수할 수 있을 것 같은 부분이므로 주의하자!

OR 연산자를 여러개 사용하는 대신, IN 연산자를 사용하는 방법도 존재한다.

SELECT *
FROM  station
WHERE local IN ('마포구','광진구')

해당 코드는 앞에서 살펴본 코드와 같은 동작을 한다! OR 을 여러번 사용해야 하는 경우가 있을 때, IN을 사용하면 코드가 더욱 간편해진다.

문자열을 검색할 때, LIKE을 사용해서 더욱 다양한 기능을 수행할 수 있다.
LIKE는 문자열의 일부분만 비교하는, 부분 검색이라고 할 수 있다.

SELECT *
From tables
WHERE country LIKE 'B%'

와 같이 사용하면, country가 B로 시작하는 데이터들만 찾아주는 것이다.
LIKE에서 %는 와일드카드로, %가 있는 곳에는 어떤 문자가 어떤 개수가 와도 상관없다.
그리고 _는 한 글자 와일드 카드로, _ 하나 당 아무 문자나 하나씩 들어갈 수 있다.
예를 들어,

SELECT *
From tables
WHERE country LIKE 'B_____'

과 같이 사용한다면, 앞의 예시에서는 Bulgary도 같이 출력되었다면, 뒤의 예시에서는 글자수가 맞는 Brasil만 출력될 것이다.
LIKE를 응용하여, 해당 문자를 포함하지 않는 문자열만 찾아내는 NOT LIKE로 쓸 수도 있다.

BETWEEN의 경우, 사이에 있는 자료를 찾아준다.
다음과 같이 사용할 수 있다.

WHERE customers BETWEEN 3 AND 5

customers 열에 있는 값이 3 이상, 5 이하인 데이터들만 찾아준다.

결측치를 찾기 위해 IS NULL도 사용할 수 있다.

where customer IS NULL

처럼 사용하면, customer가 NULL인 데이터만 찾아준다. 마찬가지로 IS NOT NULL도 가능하다.

배운 내용들을 다음과 같이 사용할 수 있다.

select station_id, name, local, address
from station
where local in('광진구','동작구','마포구','성동구','영등포구')
select color, pH, alcohol, quality
from wines
where quality >= 8 AND alcohol <= 12 AND color = 'white'
SELECT *
FROM  station
WHERE lat > (SELECT lat FROM station WHERE name = '서울북부지방법원')

사실 해당 내용은 subquery가 등장하는 내용으로, 추후 혼자 더 공부해봐야겠다!
이 링크로 서브쿼리 더 알아보고, 이 링크로 정규표현식 더 알아보자!

GROUP BY

데이터를 다룰 때, 요약하여 결과를 봐야할 일이 상당히 많다.
GROUP BY를 사용하면, 특정 column에 대해 같은 값들은 모두 하나로 그룹화 하여 보여주므로, 간단하게 한눈에 데이터를 확인할 수 있다.

GROUP BY column 으로 사용하며, group by에 사용한 column을 꼭 SELECT 절에도 사용하여야 함을 잊지 말자.
그래야만 다른 집계 값들이 어떤 그룹에 대해 측정된 값인 지를 알 수 있다.

SELECT day, SUM(total_bill), SUM(tip)
FROM tips
GROUP BY day

위와 같은 방법으로 사용한다. day에 대해 그룹화 한 후, 각각의 그룹에 대해 total_bill의 값의 합과 tip의 합을 보여준다.

여러 기준으로 그룹화하고 싶다면, 가장 우선이 되는 기준부터 순서대로 써주면 된다.

SELECT day, time, SUM(total_bill)
FROM tips
GROUP BY day, time

위의 예시는 먼저 day에 대해 그룹화 한 후, 그 안에서 또 time에 대해 그룹화 하여 데이터를 표시한다.

HAVING

HAVINGWHERE과 마찬가지로, 특정한 조건을 걸어주어 조건에 해당하는 데이터들만 뽑아낼 수 있게 한다.

단, WHERE는 그룹화가 되기 전, 각각의 데이터에 대해서 적용하는 조건임에 비해,
HAVING은 그룹화가 되고 난 후 각 그룹의 종합 값에 대해 적용하는 조건이라는 것이 다르다.

이 차이에 항상 유의하고, 조건을 걸어주려 할 때 WHERE을 사용할지, HAVING을 사용할 지 유의한다.

SELECT day, SUM(total_bill)
FROM tips
GROUP BY day
HAVING SUM(total_bill) >= 1000

위와 같은 방법으로 having을 사용할 수 있다. day에 대해 그룹화 하여 total_bill의 합을 구해 표시하는데, 이때 그 합이 1000 이상인 그룹들만 표시해준다.

만약 다음과 같은 문제가 있다고 생각해보자.

요일별로 여성의 매출액 합계를 구해주세요. 매출액이 200불 미만인 날은 출력에서 제외하세요.
-- 1. 여성이 결제한 데이터만 뽑아주세요.(WHERE 사용)
-- 2. 요일별로 매출액 합계를 구해주세요.
-- 3. 요일별로 매출액을 집계했을때 200불 미만인 날은 제외

SELECT day, SUM(total_bill)
FROM tips
WHERE sex = 'Female'
GROUP BY day
HAVING SUM(total_bill) >= 200

이 경우, 여성이 결제한 데이터라는 조건은 WHERE를 사용해 조건을 걸어주어야 하고, 매출액이 200불 미만인 날은 HAVING을 이용해 조건을 걸어주어야 한다. 이 차이에 유의한다!

ORDER BY

정보를 정렬하여 표시하고 싶을 때에는 ORDER BY를 이용한다.
ORDER BY column (DESC)로 작성하면, 해당 열에 대해 정렬해준다. 이때, 뒤에 아무것도 작성하지 않으면 기본값 오름차순(ASC)로 정렬되고, DESC를 정렬해주면, 내림차순으로 정렬할 수 있다.
정렬의 기준은 그룹화해 집계한 값도 사용할 수 있다.

SELECT day, sum(total_bill) AS revenue
FROM tips
GROUP BY day
HAVING revenue >= 1000
ORDER BY revenue DESC

그룹화해 SUM을 이용한 값을 기준으로 내림차순 정렬하였다.

SELECT day, sum(total_bill) AS revenue
FROM tips
GROUP BY day
ORDER BY revenue DESC
LIMIT 1

위와 같이, ORDER BYLIMIT를 함께 사용하면 최댓값, 혹은 최솟값을 얻어낼 수 있다.
집계함수를 이중으로 중첩하여 사용할 수 없기에, 집계함수와 ORDER BY를 사용해 이를 알아낸다. (MAX(SUM()) 불가)

예시이다.

SELECT name
FROM STUDENTS
WHERE Marks > 75
ORDER BY SUBSTR(NAME, 5)

이름의 마지막 세 글자를 기준으로 정렬하는 예시이다. 이름의 마지막 세 글자를 추출하기 위해 MYSQL의 함수를 사용하였다.
MYSQL에서 문자열을 다루는 함수는 다음과 같이 존재한다.

LEFT(컬럼명 혹은 문자열, 길이)
RIGHT(컬럼명 혹은 문자열, 길이)
SUBSTR(컬럼명 혹은 문자열, 시작 위치, 길이)

다음은 특정 column에 대해 내림차순으로 정렬하는데, 정렬할 때 소수 4째자리까지 반올림하여 표시하는 예이다.

SELECT ROUND(LONG_W, 4)
FROM STATION
WHERE LAT_N < 137.2345
ORDER BY LAT_N DESC
LIMIT 1

소수점과 관련된 기능을 하는 MySQL 함수는 다음과 같이 존재한다.

CEIL(숫자) 			: 올림
FLOOR(숫자)			: 내림
ROUND(숫자, 자릿수)	: 반올림

이렇게 1주차 SQL 강의가 끝났고 복습도 마쳤다. 생각보다 어렵지 않고 재미있었다. 옛날에 컴활 딸 때 액세스를 다룰 때 비슷한 걸 배웠던 것 같은 기억이 새록새록 난다. 다 까먹긴 했는데 ㅋㅋㅋㅋ..
SQL은 중급 강의 까지만 제공이 되기 때문에, 나의 진로를 더 탐색해보고, 어느 정도 SQL 실력을 갖추어야겠다고 판단이 되면 스스로 공부 해봐야겠다는 생각이 들었다.
사실 SQL의 중요성을 몰랐는데, 데이터 분석가든, 머신러닝 엔지니어든 많이 사용한다고 한다.
어렵지 않고 재밌게 공부할 수 있는 것 같아서 좋다!
이번주 고생했다!

profile
ai school 기간 동안의 TIL!

0개의 댓글