관리 메뉴

ilovechoonsik

[STARTERS 4기 TIL] 중간 평가 대비 Python, SQL 복습 (230309,10) 본문

STARTERS 4기 🚉/TIL 👶🏻

[STARTERS 4기 TIL] 중간 평가 대비 Python, SQL 복습 (230309,10)

춘시기좋아 2023. 3. 10. 15:11

 

📖 오늘 내가 배운 것

 

중간 평가 대비해서 Python, SQL 헷갈리는 개념들 총 정리!
 

 

1.1 데이터와 정보

구분 내용 예시
데이터 객관적 사실을 수집하여 모아놓은 자료 블로그 방문기록
정보  데이터 가공하여 의미 도출된 것 일일 방문자 수, 성별 방문자 수, 시간대별 방문자 수
지식 정보에 개인적 경험을 결합시킨 새로운 지식 방문자가 많은 성별/나이에 대한 원인 파악
지혜  지식에 아이디어가 결합된 창의적 산물 방문자가 많은 성별/나이를 타겟으로 운영 전략 수립

 

 

1. Python

1 람다 표현식

- 매개변수와 수식으로 이루어진 함수!

lambda 매개변수1, 매개변수2, .... : 수식

 

 

2.1  subset 생성할 때 데이터 찾는, 뽑는 방법들

정규식!

라이브러리 불러오기

import re

 

메타문자

[ ]
문자클래스 [ ] 사이의 문자들과 매치
- [From - To] ex) 
[a-zA-Z] = 알파벳 모두
[0-9] = 모든 숫자

\d 숫자 = [0-9]
\D 숫자가 아닌 것 = [^0-9]
\s 공백 = [ \n\t\r\f\v]
\S 공백이 아닌 것 = [^ \n\t\r\f\v]
\w 문자+숫자+_ = [a-zA-Z0-9_]
\W 문자+숫자+_가 아닌 것 =[^a-zA-Z0-9_]
\ 이스케이프
\와 함께 사용하면 일반 문자로 인식된다.
 
. \n를 제외한 모든 문자 . = 모든 문자
[.] []안에 .을 넣을 경우 그냥 '.'으로 인식 [.] = 온점.
| or  
^ [] 바깥에 있을 경우 문자열의 시작과 매치
re.MULTILINE과 함께 쓰인다면 각 줄의 첫 문자와 일치
ex)
^a = a로 시작하는
[^] [] 안에 있을 경우 [] 안의 정규표현식을 부정(not)한다. ex)
[^123] = 123이 아닌 것
$ 문자열의 끝과 매치
re.MULTILINE과 함께 쓰인다면 각 줄의 끝 문자와 일치
 
* 반복 (0 ~ ∞) ex)
mizy* = miz / mizy / mizyyyyy
+ 반복 (1 ~ ∞) ex)
mizy+ = mizy / mizyy
? 있어도 되고 없어도 된다. (0 또는 1) ex)
miz?y = miy / mizy
{m} m번 반복 ex)
mizy{3} = mizyyy
{x, y} x ~ y번 반복 ex)
mizy{2, 4} = mizyy / mizyyy

 

 

(1) str, find 사용 - boolean indexing

# 서울시 구별 인구수 시각화
# 구 (11 로 시작하면 구 이기 때문에 str과 문자열 함수 find 사용하여 True로 반환받는다
# 그 값이 0 보다 클 것이기 때문에 조건을 걸고 boolean indexing!
df_seoul = df[df['행정구역'].str.find('구 (11')>0].copy()

# 구 별로 데이터를 그룹화 할 것이기 때문에 str-split을 통해 분리하고
# 그 중 str[1]번째 데이터를 가져온다,
df_seoul['구'] = df_seoul['행정구역'].str.split(' ').str[1]


# 동별 인구수 시각화
# 송파구 동별 인구수 시각화
df_song['동'] = df_song['행정구역'].str.split(' ').str[2].str.split('(').str[0]
df_song

 

(2) str.contains - boolean indexing

  • 컬럼.str.contains(문자열) : 문자열이 포함된 데이터 추출
df_sido = df[df['행정구역'].str.contains('00000000')].copy()

 

(3) groupby 후 값없어서 생략된 연도 포함시키기

# 연도별 폭염일수 : 연도로 그룹핑하여 일수 카운트
df_seoul_hotday_count = df_seoul_hotday.groupby(df_seoul_hotday['일시'].dt.year)['일시'].count().to_frame()

# 폭염일이 없는 날을 포함시키기 위하여 1911~2020년의 연도 데이터프레임 생성
df_years = pd.DataFrame(range(1911,2021))
df_years.index = df_years[0]
df_years

# 연도별 폭염일수, 연도 데이터프레임 concat
df_seoul_hotday_count = pd.concat([df_seoul_hotday_count,df_years], axis=1)
df_seoul_hotday_count

 

(4) str -> int 자료형 일괄 변경

for i in range(101):
    df.iloc[:,i] = df.iloc[:,i].str.replace(',','').astype('int64')

# df의 모든행의 100까지의 열을 각각 돌면서 , 을 뺴버리고 int64로 변경!
# 이걸 df.iloc[:,i] i에 맞춰 전부 적용

 

(5) index 가지고 데이터 삭제하기

계약이 된 상태인 행들만 보고 싶다! 해제사유발생한 행(notnull())은 날려줘라~

 

df = df.drop(index=df[df['해제사유발생일'].notnull()].index)

 

(6) 컬럼의 중복되지 않는 고유한 값들만 보려면 + 볼 수 있는 행 수 늘리기 (=저번 🥓)

df_store_class = df_store[['상권업종대분류명','상권업종중분류명','상권업종소분류명']].drop_duplicates().sort_values(['상권업종대분류명','상권업종중분류명','상권업종소분류명'])

# 상권업종 분류표 모두보기(최대 행 수 지정)
pd.options.display.max_rows=20

 

 

 

2. map 함수

- map은 리스트나 튜플의 각 요소를 지정된 함수로 처리해 주는 함수이다.

  • 원본리스트를 변경하지 않고 새 리스트를 생성한다.
  • list(map(함수, 리스트))
  • tuple(map(함수, 튜플))

 

- 람다 표현식에 조건부 표현식 사용

  • lambda 매개변수들 : 식1 if 조건식 else 식2
# 아래 리스트에서 짝수는 float로 바꾸고, 홀수는 str로 바꾸기
l1 = [1,2,3,4,5,6,7,8,9,10]

list(map((lambda x:float(x) if x%2==0 else str(x)),l1))
# 들어온 매개변수 x가 짝수라면 -> float(x)
# else -> str(x)
['1', 2.0, '3', 4.0, '5', 6.0, '7', 8.0, '9', 10.0]

 

3. 클래스, 객체 class

2. map 함수

 

4. 데이터 프레임 만드는 방법

1. 리스트로 만들기 pd.DataFrame(2차원리스트, columns=컬럼리스트, index=인덱스리스트)

2. 딕셔너리로 만들기 pd.DataFrame(딕셔너리, index=인덱스리스트)

3. csv, excel 등등 문서 읽어오

 

미리 보기

- head(n) : 가장 위 n개 행

- tail(n) : 가장 뒤 n개 행

- sample(n) : 랜덤 n개 행 (비율로 보려면 frac=비율(0.n))

- nlargest(갯수,컬럼명) : 컬럼에서 지정한 개수의 높은 순 보기 (컬럼의 데이터가 숫자형일 때 사용할 수 있다.)

- nsmallest(갯수,컬럼명) : 낮은 순 보기 (컬럼의 데이터가 숫자형일 때 사용할 수 있다.)

 

요약 보기

- shape : 행, 열 크기 보기

- len(데이터프레임) : 데이터 갯수 보기

- columns : 컬럼명 보기

- index : 인덱스 보기

- dtypes : 데이터 자료형 보기 (판다스에서는 문자열의 데이터타입이 object)

- info() : 데이터프레임 정보 보기 (데이터프레임의 총 샘플 갯수, 컬럼 수, 컬럼 별 정보 등)

- 컬럼.unique() : 컬럼의 유니크한 데이터 뽑기 (개수는 nuique)

- 컬럼.value_counts() : 컬럼의 유니크한 값의 갯수

- describe() : 요약통계 보기

 

5  조건에 따라 데이터 추출하기

  • boolean index  '&' , '|' ,'~', '^' 
  • 컬럼.isin(값리스트)
  • 컬럼.isnull() --> 해당 컬럼의 값이 null인 데이터 추출
  • 컬럼.notnull() --> 해당 컬럼의 값이 null이 아닌 데이터 추출

6. 행 데이터 추출

loc iloc
df.loc[인덱스] 시리즈 형태로 추출 df.iloc[행번호] 시리즈 형태로 추출
df.loc[인덱스리스트]  데이터프레임 형태로 추출 df.iloc[행번호리스트] 데이터프레임 형태로 추출
df.loc[인덱스명슬라이스] 행 전체 추출, 슬라이스 시에도 인덱스 이름 사용해야 함 df.iloc[행번호슬라이스] 슬라이스로 범위 지정 추출
# 인덱스가 i1,i3,i5인 행 추출
df.loc[['i1','i3','i5']]

# 인덱스가 i3인 행을 데이터프레임 형태로 추출
df.loc[['i3']]

# 인덱스가 i3인 행 이후의 모든 행 추출
df.loc['i3':]
# 짝수 행번호의 데이터 추출
df.iloc[::2]


# 홀수 행번호의 데이터 추출
df.iloc[1::2]


# 1,3,5행 슬라이스
df.iloc[1:6:2]

# 마지막 2개 행 추출하기(리스트)
df.iloc[[-2,-1]]

 

7. 행, 열 데이터 추출

행 데이터 추출에서 사용했던 기법을 ,로 구분시켜 컬럼에 대해서도 사용가능
loc[인덱스명, 컬럼명] (리스트 및 슬라이싱도 가능)

iloc[인덱스 번호, 컬럼 번호] (리스트 및 슬라이싱도 가능)

loc iloc
# 인덱스 i1의 kor점수
df.loc['i1','kor']

# 인덱스 i1,i3,i5의 name, kor
df.loc[['i1','i3','i5'],['name', 'kor']]

# 모든 행에서 'name','math' 가져오기
df.loc[:,['name','math']]

# 인덱스 i7 이후의 행에서 'name' 가져오기(데이터프레임)
df.loc['i7':,['name']]

# 0번째 행, 0번째 열
df.iloc[0,0]

# 1,3,4번째 행 name, eng
df.iloc[[1,3,4],[0,2]]

# 1,3,5번째 행 0,2번째 열 슬라이싱
df.iloc[1:6:2, :3:2]

# 마지막행 1,3열 슬라이싱
df.iloc[-1,1:4:2]

# 모든행, 1,2열 
df.iloc[:,[1,2]]

 

8 열 추가/삭제/변경

표로 열과 행이 각각 어떤 경우에 어떤 함수 쓰는지 정리 -> append, rename, drop

  사용법 예시
열 추가 df[column] = 추가할데이터
# 컬럼이 존재하면 추가, 존재하지 않으면 수정된다.
# 학생 번호 추가하기 (1부터 시작하여 1씩 증가)
df['no'] = range(1,len(df)+1)
열 수정 df[column] = 수정할데이터 # 학생 번호 수정하기 (100부터 시작하여 1씩 증가)
df['no']  = df['no']+99
열 삭제 df.drop(columns=삭제할컬럼리스트, inplace=True)
# 존재하지 않는 열은 삭제할 수 없다.
# no, sum column 삭제
df.drop(columns=['no','sum'], inplace=True)
컬럼명 한번에 수정 df.columns = 컬럼명리스트
# 컬럼명리스트의 항목 수는 컬럼 수와 동일해야한다.
#'이름','국어','영어','수학'
df.columns=['이름','국어','영어','수학']
특정 컬렴명만 수정 df.rename(columns={'현재컬럼명1':'바꿀컬럼명1','현재컬럼명2':'바꿀컬럼명2',...}) # 이름-->성명
df = df.rename(columns={'이름':'성명'})

 

 

9 행 추가/삭제/변경

  사용법 예시
행 추가 후 인덱스 재지정 df.append(추가할데이터, ignore_index=True)
# 추가할 데이터는 딕셔너리 형태로 전달 : {컬럼1:값1, 컬럼2:값2,...}
# 데이터프레임의 끝에 행 추가
# 기존 인덱스는 무시하고, 인덱스가 새롭게 생성된다.
new_value = {'name':'Python','kor':80,'eng':90,'math':100}
df = df.append(new_value,  ignore_index=True)

# ignore_index=True 기존 인덱스 무시하고 새로 생성하겠다는 뜻
인덱스 지정하여 추가/수정 df.loc[인덱스] = 추가할데이터
df.loc[인덱스] = 수정할데이터
# 인덱스가 존재하면 해당 인덱스의 데이터가 수정된다.
# 인덱스가 존재하지 않으면 데이터프레임의 끝에 데이터가 추가된다.
# 인덱스 35에 추가
df.loc[35] = ['aaa',70,80,90]

# 인덱스 30에 추
df.loc[30] = ['ccc',60,70,80]
행 삭제 df.drop(index=[삭제할인덱스리스트], inplace=True) # 30,34,35 삭제
df.drop(index=[30,34,35], inplace=True)
전체 인덱스명 변경 df.index = 인덱스명리스트
인덱스명리스트의 항목 수는 인덱스 수와 동일해야한다.
# range(100,3100,100)
df.index = range(100,3100,100)
특정 인덱스명 변경하 df.rename(index={'현재컬럼명1':'바꿀컬럼명1','현재컬럼명2':'바꿀컬럼명2',...}) # 100-->'a', 200-->'b'
df.rename(index={100:'a',200:'b'}, inplace=True)

 

 

10 함수로 컬럼의 데이터 변경하기

  • 컬럼.apply(함수명)
  • 컬럼.apply(함수명, 매개변수명=매개변수값)
    매개변수명을 명시해주어야 한다.
  • 적용할 함수가 미리 정의되어 있어야 한다.

예시1

# 1. df['math']의 모든점수에 5점 더하기.(--> 105점?)
df_copy['math'] = df.math+5
df_copy


# 2. df['math']의 모든점수에 5점 더하기. 100점이 넘을 수 없다.
def plus5(x):
    score = x+5
    if score>=100:
        score=100
    return score

df_copy['math'] = df['math'].apply(plus5)
df_copy
# plus5의 매개변수 x는 df['math'] 데이터를 받는 매개변수!
# 때문에 apply 할 때는 함수명만 전달해주면 된다~

11 행/열 데이터 집계하기

  • 데이터프레임.apply(함수명, axis=0) : 열단위로 함수가 적용된다.
  • 데이터프레임.apply(함수명, axis=1) : 행단위로 함수가 적용된다.
# 합계 구하기
def get_sum(x):
    return x.sum()
# 행, 열 단위 데이터가 들어오면 합계 구해서 return

행 단위 적용 - 학생 별 점수 합계

df_copy['sum'] = df.apply(get_sum, axis=1)

 

 

 

 

 

 

 

 

열 단위 적용 -  과목 별 점수 합계

df_copy.loc['sum'] = df.apply(get_sum, axis=0)

 

 

 

12 결측치

NaN, 값이 없는 것! : 통계값을 구할 때 데이터의 개수에 영향을 끼치므로 적절한 처리 필요

df.isnull().sum() : 널값 개수

df.info() : 전체 정보

dropna() : 삭제

fillna() : 대치

방법 문법 예시
결측치 삭제 df.dropna() 
: 결측치가 존재하는 모든 행 삭제

df.dropna(axis=1) 
: 결측치가 존재하는 모든 열 삭제
 
결측치 대치
특정 값으로 df.fillna(특정값) df.fillna(0) -> 전부 0 으로
이전 값으로 df.fillna(method='ffill') 이전 값 없으면 대치 X, 그대로 NaN
다음 값으로 df.fillna(method='bfill') 다음 값 없으면 대치 X, 그대로 NaN
컬럼별로 대치할 값 지정 df.fillna({'컬럼명1':값1, '컬럼명2':값2,...}) df.fillna({'A':0,'B':1,'C':2,'D':3})

📌 결측치가 포함된 데이터의 통계값?

- 결측치는 없는 데이터로 간주된다.

df['A'].mean() # 3.0
df['B'].mean() # 3.0

 

13 자료형 종류

int64 : 정수형

float64 : 실수형

bool : 부울형

object : 문자열

category : 카테고리

datetime64 : 날짜, 시간

 

14 자료형 처리

방법 문법 예시
자료형 확인 데이터프레임 : df.dtypes
시리즈 : series.dtype

시리즈 데이터 타입 혼합 -> object

시리즈 정수와 실수 혼합 -> float64
시리즈의 경우 : df['int'].dtype
혼합의 경우 : type(df.loc[행,열])
자료형 변환 df.astype('자료형')
series.astype('자료형')
전체 자료형 변환
: df = df.astype('자료형')

object에서 int로
: df = df.astype('float').astype('int') 
object인 데이터를 바로 int로 바꾸는 건 불가능! float으로 바꾸고 int로 넘긴다

특정 컬럼의 자료형 변환
: df['col'] = df['col'].astype('자료')
# 숫자형으로 변환 pd.to_numeric(col, errors='ignore')
: 숫자로 변경할 수 없는 값이 있으면 작업하지 않음

pd.to_numeric(col, errors='coerce')
: 숫자로 변경할 수 없는 값이 NaN으로 설정

pd.to_numeric(col, errors='raise')
: 숫자로 변경할 수 없는 값이 있으면 에러발생(default)
- pd.to_numeric(s2, errors='ignore')
0 1.0
1 2
2 a
dtype : object

- pd.to_numeric(s2, errors='coerce')
0 1.0
1 2.0
3 NaN
dtype : float64
# 시계열 데이터로 변환 pd.to_datetime(col) - astype
df['출생'] = df['출생'].astype('datetime64')

- to_datetime
df['사망'] = pd.to_datetime(df['사망'])

 

 

 (2) 카테고리형 다루기

목적 사용법 예시
카테고리형으로 변환 컬럼.astype('category') # 자료형 변환하기
df['grade'] = df['grade'].astype('category')
카테고리 요소 이름 바꾸기 컬럼.cat.categories = 카테고리리스트 # 1234 등급을 ABCD로
df['grade'].cat.categories = ['A','B','C','D']
카테고리 추가 컬럼.cat.set_categories(카테고리리스트) # F 끼워넣기
df['grade'] = df['grade'].cat.set_categories(['A','B','C','D','F'])

데이터 용량을 절약할 수 있다는 장점!

 

(1) 시계열 데이터?

 

Pandas에서 날짜와 시간을 다루는 자료형

 

목적 사용법 예시
컬럼을 datetime 자료형으로 변경 pd.to_datetime(컬럼) # 출생, 사망 컬럼을 datetime 자료형으로 변경하기
df['출생'] = pd.to_datetime(df['출생'])
연, 월, 일 분기 추출 컬럼.dt.year
컬럼.dt.month
컬럼.dt.day
컬럼.dt.quarter
year : 1962, 1953 ...
month : 1, 2, 3 ...
day : 20, 21 ...
quarter : 1,2,3,4
날짜 계산 긴 날짜 - 짧은 날 # 연산 시 최소 단위로 결과값 반환
df['생존일수'] = df['사망']-df['출생']
: 24213 days

# 생존기간 컬럼 만들기
df['생존기간'] = df['사망'].dt.year-df['출생'].dt.year
: 56
요일, 월이름 추출 컬럼.dt.strftime('%a') : 요약된 요일이름
컬럼.dt.strftime('%A') : 긴 요일이름
컬럼.dt.strftime('%w') : 숫자요일(0:일요일)
컬럼.dt.strgtime('%b') : 요약된 월이름
컬럼.dt.strftime('%B') : 긴 월이름
%a : Thu, Fri ...
%b : Jan, Feb ...
datetime 자료형을 인덱스로 만들어 사용 df.index = df['컬럼'] # 출생 컬럼을 인덱스로 만들기
df.index = df['출생']
# 1955년 출생한 사람 데이터 추출하기
df.loc['1955']

# 1955년 2월 출생한 사람 데이터 추출하기
df.loc['1955-02']

 

 

15 데이터프레임 연결하기 concat

  • pd.concat(데이터프레임리스트)
    데이터프레임이 동일한 컬럼명 기준으로 행으로 연결된다.
  • pd.concat(데이터프레임리스트axis=1)
    데이터프레임이 동일한 인덱스 기준으로 열로 연결된다

 

7.2 공통된 열 기준으로 연결하기 merge

  • pd.merge(left,right,on=기준컬럼,how=연결방법)
  • 2개의 데이터프레임을 연결한다.

 

16 행/열 형태 변경 (melt, pivot)

행을 열로(값으로) 보내기! melt

  • 데이터프레임.melt()
  • pd.melt(데이터프레임)

 

열을 행으로 보내기! pivot

  • df.pivot( index=인덱스로 사용할 컬럼, columns=컬럼으로 사용할 컬럼, values=값으로 사용할 컬럼 )

샘플데이터 생성

# 샘플데이터
df = pd.read_csv('data/scores.csv')
df = df.head(2)
df = df.melt(id_vars = 'name', var_name='subject',value_name='score')

def get_grade(x):
    if x>=90: grade='A'
    elif x>=80: grade='B'
    elif x>=70: grade='C'
    elif x>=60: grade='D'
    else: grade='F'
    return grade

df['grade'] = df['score'].apply(get_grade)
df = df.sort_values('name')
df

 

예시 1. 인덱스=name, 컬럼=subject, values=score

df.pivot(index='name', columns='subject',values='score')

적용 전 / 적용 후

 

예시 2. 인덱스=name, 컬럼=subject, valyes=[score, grade]

df.pivot(index='name', columns='subject',values=['score','grade'])

적용 전 / 적용 후

17 분석하며 사용

중복 제거 drop_duplicates

# 고유 특정 문자열이 포함되어있는지 확인 : .str.contains(문자열)품목 목록
df_items =df[['품목 번호','품목 이름']].drop_duplicates()
df_items = df_items.sort_values('품목 이름')

# 고유한 시장/마트의 목록
df_market = df[['시장/마트 번호','시장/마트 이름','자치구 이름','시장유형 구분(시장/마트) 이름']].drop_duplicates()

 

문자열 포함 확인 str.contains

 

# 2021-06 데이터 이용
df_sam = df[ (df['품목 이름'].str.contains('삼겹살')) & (df['년도-월']=='2021-06') & (df['실판매규격'].str.contains('600g')) ]
df_sam

 

to_datetime 에러 처리 errors = coerce 에러 유발하는 녀석들 NULL로

# errors = coerce 사용해서 에러 유발하는 녀석들 NULL 처리
df['반납일시'] = pd.to_datetime(df['반납일시'], errors='coerce')

 

- datetime 함수

dt.date

dt.year 등으로 뽑기

 

#요일컬럼 추가 : strftime('%a') -> 14.서울시 공공자전거
df_207['대여요일'] = df_207['대여일시'].dt.strftime('%a')

 

 

18 시각화

plt, subplot : https://ilovechoonsik.tistory.com/216?category=1158849

그래프 강조, seaborn : https://ilovechoonsik.tistory.com/218

 

목적에 따라 사용되는 그래프 종

시각화 목적 그래프 종류
시간에 따른 변화 plot
크기 비교/순위 bar(h)
데이터 비율 pie
데이터 분포 표현 histogram, boxplot, violinplot, heatmap
데이터 관계 scatter
지역 hexagonal, folium

산점도

plt.scatter(x,y,s=,c=,cmap)

s : 사이즈, 사이즈 기

c : 색상 or cmap 사용 시 cmap 색상 기준

 

히트맵

plt.pcolor(df, cmap=~)

sns.heatmap

 

히스토그램

plt.hist

 

 

2.2 bar

용도 파리미터
막대 폭 지정 세로 
width = 0~1사이의 실수(default:0.8)


가로
height = 0~1사이의 실수(default:0.8)
막대 테두리 edgecolor = 테두리 색상
linewidth = 테두리 두께
막대 색상 color
막대 패턴 hatch='/', '', '|', '-', '+', 'x', 'o', 'O', '.', '*'
(패턴기호 개수로 밀도 조정)
막대 위치 지정 align = center/edge (default=center)
edge로 지정하면 막대의 왼쪽 끝과 틱을 맞춘다.
막대의 오른쪽 끝과 틱을 맞추려면 width를 음수로 지정한다.

 

19 subplot

4가지 방법

1. 도화지 그려놓고 냅다 때려박기

2. 도화지 그려놓고 위치 지정하기

3. 행,열로 쪼개서 그리기 [행번호][열번호] 접근

4. 객체 생성할 때 (전체행개수, 전체열개수, 순서 지정)

 

1. 냅다 떄려박기

1) 전체 그래프의 크기를 정한다. (정하지 않으면 디폴트 크기로 지정된다.)
plt.figure(figsize=(x사이즈, y사이즈))

2) 그래프를 그려 넣을 격자를 지정한다.(전체행개수,전체열개수,그래프순서)
plt.subplot(전체행개수,전체열개수,그래프순서)

3) 격자에 그래프를 하나씩 추가한다.

plt.figure(figsize=(9,6))
plt.subplot(221)
plt.plot(df1['x'],df1['y'],'o')

plt.subplot(222)
plt.plot(df2['x'],df2['y'],'+')

plt.subplot(223)
plt.plot(df3['x'],df3['y'],'*')

plt.subplot(224)
plt.plot(df4['x'],df4['y'],'d')

 

1.  pyplot으로 subplot 그리기

  • figure 객체를 변수에 받는다.
  • figure객체의 suptitle(제목)메소드로 전체 그래프의 제목을 표시한다.
  • figure객체의 tight_layout()메소드로 그래프의 간격, 너비를 최적화한다.
# plt.figure() : figure(도화지) 객체 생성
# fig에 전체 도화지 객체 담기
fig = plt.figure(figsize=(9,6), facecolor='ivory')

plt.subplot(221)
plt.plot(df1['x'],df1['y'],'o')
plt.title('ax1')

plt.subplot(222)
plt.plot(df2['x'],df2['y'],'+')
plt.title('ax2')

plt.subplot(223)
plt.plot(df3['x'],df3['y'],'*')
plt.title('ax3')

plt.subplot(224)
plt.plot(df4['x'],df4['y'],'d')
plt.title('ax4')

fig.suptitle('Amscombe', size=20)
fig.tight_layout() # figure 간 간격 최적화

 

2. 위치, 크기 지정해서 subplot 그리기

2.1 figure, axes

  • figure : 그림이 그려지는 캔버스
  • axes : 하나의 그래프 (각 subplot을 그리기 위한 틀!) 각각 객체로 받아 사용

 

2.2 위치, 크기 지정하여 그래프 그리기

 

1) figure 객체를 생성한다.

fig = plt.figure(figsize=(가로길이,세로길이))


2) figure객체의 add_axes 메소드로 위치와 크기를 지정하여 axes 객체를 생성한다.

ax1 = fig.add_axes([left, bottom, width, height])
# left, bottom : 상대적인 시작 위치 (figsize의 크기를 1이라고 했을 때 상대적 위치)
# width, height : 상대적인 크기(figsize의 크기를 1이라고 했을 때 상대적 크기)

3) axes에 그래프를 그린다. 

ax1.plot(x,y)

 

4) axes에 제목 추가.

ax1.set_title(제목)

# plt~ 해서 그렸던 그래프와 다르게 객체 지향으로 그린다.

 

2.3 위치와 크기를 자유롭게 지정하여 axes 객체 만들기

  • add_axes를 사용하면, 서브플롯의 크기와 위치를 자유롭게 지정할 수 있다.
  • 그래프를 겹쳐그리거나, 크기가 각각 다른 그래프를 그릴 수 있다.
# 1)figure 객체를 생성한다.
fig = plt.figure(figsize=(8,6))

# 2) figure객체의 add_axes 메소드로 위치와 크기를 지정하여 axes 객체를 생성한다.
ax1 = fig.add_axes([0,0.5,0.4,0.4])
ax2 = fig.add_axes([0.5,0.5,0.4,0.4])
ax3 = fig.add_axes([0,0,0.4,0.4])
ax4 = fig.add_axes([0.5,0,0.4,0.4])

# 3) axes에 그래프를 그린다.
ax1.plot(df1['x'],df1['y'],'o')
ax2.plot(df2['x'],df2['y'],'r^')
ax3.plot(df3['x'],df3['y'],'k*')
ax4.plot(df4['x'],df4['y'],'m+')

# 4) axes에 제목 추가.
ax1.set_title('ax1')
ax2.set_title('ax2')
ax3.set_title('ax3')
ax4.set_title('ax4')

 

3. axes를 행, 열로 쪼개어 서브플롯 그리기

  • plt.subplots() 함수를 호출하면 figure, axes 객체를 생성하여 튜플 형태로 반환한다.
fig, ax = plt.subplots()


1) axes 객체를 행,열로 쪼개어 생성하기

fig, ax = plt.subplots(nrows=행개수, ncols=열개수,figsize=(가로사이즈,세로사이즈))


2) axes[행번호][열번호] 형태로 접근하여 그래프 그리기

3) 서브플롯간 축을 공유할 수 있다.

sharex=True, sharey=True

 

3.1 예시

# 1) axes 객체를 행,열로 쪼개어 생성하기
# 3) 서브플롯간 축을 공유할 수 있다.
fig,ax = plt.subplots(nrows=2, ncols=2, figsize=(8,6), sharex=True, sharey=True, facecolor='pink')

# 2) axes[행번호][열번호] 형태로 접근하여 그래프 그리기
ax[0][0].plot(df1['x'],df1['y'],'o')
ax[0][1].plot(df2['x'],df2['y'],'^')
ax[1][0].plot(df3['x'],df3['y'],'*')
ax[1][1].plot(df4['x'],df4['y'],'d')

# 4) 각 그래프에 제목 추가
ax[0][0].set_title('ax1')
ax[0][1].set_title('ax2')
ax[1][0].set_title('ax3')
ax[1][1].set_title('ax4')

# 4) 각 그래프에 그리드 추가
ax[0][0].grid(ls=':')
ax[0][1].grid(ls=':', color='pink')
ax[1][0].grid(ls=':', color='skyblue')
ax[1][1].grid(ls=':', color='green', alpha=0.5)

# 6) 그래프 전체 제목
fig.suptitle('Anscombe', size=20)

# 7) 그래프 간격, 크기 최적화
fig.tight_layout()

 

4. 전체 행 열과 그래프 순서에 따라 서브플롯 그리기

1) figure 객체를 생성한다.

fig=plt.figure()


2) 서브플롯을 그릴 axes 객체를 생성한다.

ax = fig.add_subplot(전체행개수,전체열개수,순서)



3) axes 객체에 그래프를 그린다.

ax.plot(x,y)

 

4) 축 공유하기 : 어떤 axes의 축을 공유할 것인지 지정한다.

sharex=axes객체, sharey=axes객체

 

4.1 예시

# 1) figure 객체를 생성한다.
fig = plt.figure(figsize=(9,6), facecolor='ivory')

# 2) 서브플롯을 그릴 axes 객체를 생성한다.
ax1 = fig.add_subplot(2,2,1)
ax2 = fig.add_subplot(2,2,2, sharex=ax1, sharey=ax1)
ax3 = fig.add_subplot(2,2,3, sharex=ax1, sharey=ax1)
ax4 = fig.add_subplot(2,2,4)


# 3) axes 객체에 그래프를 그린다.
# 4) 축 공유하기 : 어떤 axes의 축을 공유할 것인지 지정한다.
ax1.plot(df1['x'],df1['y'],'o', label='ax1')
ax2.plot(df2['x'],df2['y'],'^', label='ax2')
ax3.plot(df3['x'],df3['y'],'*', label='ax3')
ax4.plot(df4['x'],df4['y'],'+', label='ax4')

# 4) 틱 변경하기
ax4.set_xticks(range(1,20,1))
ax4.set_yticks(range(1,15,1))

# 5) 범례 표시하기
ax1.legend(loc=2)
ax2.legend(loc=2)
ax3.legend(loc=2)
ax4.legend(loc=2)

# 6) figure 제목 추가하기
fig.suptitle('Anscombe', size=20)

# 8) 그래프 크기,간격 최적화하기
fig.tight_layout()

plt.show()

 

 

# 그래프를 이미지로 저장하려면?

  • fig.savefig(파일명, dpi=해상도)
  • 해상도 default : 100

 

- str.find!

# 구 (11 로 시작하면 구 이기 때문에 str과 문자열 함수 find 사용하여 True로 반환받는다
# 그 값이 0 보다 클 것이기 때문에 조건을 걸고 boolean indexing!
df_seoul = df[df['행정구역'].str.find('구 (11')>0].copy()

 

- ,삭제 및 데이터 타입 한번에 변경

for i in range(101):
    df.iloc[:,i] = df.iloc[:,i].str.replace(',','').astype('int64')

 

mutable vs immutable -> 주피터 깊은복사와얇은복사

  • 얕은복사(shallow copy) : 객체의 메모리를 새로 할당. 하위 객체의 메모리는 그대로.
  • 깊은복사(deep copy) : 객체와 하위 객체들의 메모리를 새로 할당.

 

 

 

2. SQL

DML : 데이터 조작어 - 검색 및 수정

SELECT INSERT UPDATE DELETE MERGE

 

DDL : 데이터 구조 다루기 - 구조 생성 변경 삭제

CREATE ALTER, DROP, RENAME

 

DCL : 데이터에 대한 권한 관리

GRANT REVOKE

 

아래 결과는?
-- NULL인 문자열 결합
SELECT CONCAT("전화번호: ", phone )
FROM customer;

-> NULL 결합시 결과값 NULL

 

 

 

내장함수 - 제곱

power(숫자, 제곱)

MOD(m,n)함수 : m을 n으로 나누어 나머지 값 반환

FLOOR(n) : 주어진 값보다 작거나 같은 최대 정수를 구하는 함수

CEIL(n) : 주어진 값보다는 크지만 가장 근접하는 최솟값을 구하는 함수

 

- 문자열 결합

CONCAT(문자열, 문자열,…): 공백 없이 문자열들만 결합한다.
CONCAT(구분자,문자열, 문자열,…): 구분자로 문자열을 결합한다
SELECT GROUP_CONCAT(묶을 컬럼 [, 데이터1, 데이터2 ...]) 
FROM 테이블명
- 컬럼에서 NULL이 아닌 모든 값을 콤마(,)로 합쳐 하나의 문자열로 가져오는 함수
- 컬럼에 추가로 데이터1,2를 붙인 다음에 결합

 

- 문자열 길이

LENGTH(문자열): 문자열의 Byte 길이
CHAR_LENGTH(문자열): 문자의 개수

 

- 대소문자

UPPER(문자열) : 대문자로 변환한다.
LOWER(문자열) : 소문자로 변환한다.

 

- 문자열 추출

-- 안녕하세요 문자열에서 2~3 번 인덱스 문자를 추출
select substring('안녕하세요', 2,3);
-- 안.녕.하.세.요 문자열에서 . 를 만난후 2번째 까지
select substring_index('안.녕.하.세.요', '.', 2);
-- 안.녕.하.세.요 문자열에서 . 를 만난후 뒤에서 -3번째 까지
select substring_index('안.녕.하.세.요', '.', -3);
SELECT LEFT('안녕하세요', 3);
SELECT RIGHT('안녕하세요', 3);

 

- 날짜 자료형 다루기

YEAR(날짜), MONTH(날짜), DAY(날짜), HOUR(시간), MINUTE(시간), SECOND(시간), 
MICROSECOND(시간), LAST_DAY(날짜)

 

- 날짜/시간 증감 함수

date를 기준으로 INTERVAL expr 만큼 더하거나 뺀다

DATE_ADD(date,INTERVAL expr)
DATE_SUB(date,INTERVAL expr) 
ADDDATE(date,INTERVAL expr),
SUBDATE(date,INTERVAL expr)

 

time를 기준으로 expr 만큼 더하거나 뺀다
ADDTIME(time, expr),
SUBTIME(time, expr) 


날짜 date에 type 형식으로 지정한 expr값을 더하거나 뺀다
DATE_ADD()와 ADDDATE()는 같은 동작이고, DATE_SUB()와 SUBDATE()는 같은 의미이다

 

 

- 날짜/시간 사이의 차이와 월/요일/주 값
DATEDIFF(날짜1, 날짜2) 날짜1-날짜2의 차이를 반환
TIMEDIFF(시간1, 시간2 ) 시간1-시간2의 차이를 반환
DAYOFWEEK(날짜) 요일(1: 일~7: 토) 반환
MONTHNAME( ) 월의 영문(January ~December) 반환
DAYOFYEAR(날짜) 1년 중 몇 번째 날(1~366)인지를 반환
TIME_TO_SEC(시간) 시간을 초 단위로 반환

 

- 날짜 형식 반환

DATE_FORMAT(날짜,format) 날짜를 format 형식으로 반환한다.

 

- 데이터 형식 변환 함수

CAST(expression AS 데이터형식 [(길이)]) 
CONVERT(expression, 데이터형식 [(길이)])

 BINARY
 CHAR
 DATE
 DATETIME
 TIME
 SIGNED {INTEGER}
 UNSIGNED {INTEGER}

 

• 구매 가격을 정수로 출력

SELECT CAST(AVG(saleprice) AS SIGNED INTEGER)
AS '평균 구매 가격' FROM orders;
SELECT CONVERT(AVG(saleprice), SIGNED INTEGER) AS '평균 구매 가격' 
FROM orders;

 

SELECT CAST('2020-10-19 12:35:29.123' AS DATE)AS 'DATE'; > 2021-01-20
SELECT CAST('2020-10-19 12:35:29.123' AS TIME)AS 'TIME'; > 10:10:30
SELECT CAST('2020-10-19 12:35:29.123' AS DATETIME)AS 'DATETIME'; 2021-~~~ 10:10 ~~

 

- 상관 부속질의(correlated subquery)
• 상위 부속질의의 투플을 이용하여 하위 부속질의를 계산함. 
즉 상위 부속질의와 하위 부속질의가 독립적이지 않고 서로 관련을 맺고 있음.
예) 출판사별로 출판사의 평균 도서 가격보다 비싼 도서를 구하시오.
SELECT b1.bookname
FROM Book b1
WHERE b1.price > (SELECT avg(b2.price)
FROM Book b2
WHERE b2.publisher=b1.publisher);

 

- From 절에서 서브쿼리 사용하기
• FROM절 안에 쓴 서브 쿼리의 결과는 뷰처럼 취급
• 인라인 뷰(Inline View)라고도 한다.

 

- NULL 관련 처리 방안

IFNULL(컬럼명, 컬럼 NULL일 때 사용 값)

 

- NULL 값이란?
아직 지정되지 않은 값
NULL 값은 ‘0’, ‘’ (빈 문자), ‘ ’ (공백) 등과 다른 특별한 값
NULL 값은 비교 연산자로 비교가 불가능함
NULL 값의 연산을 수행하면 결과 역시 NULL 값으로 반환됨

 

집계 함수를 사용할 때 null 주의할 점
‘NULL+숫자’ 연산의 결과는 NULL
집계 함수 계산 시 NULL이 포함된 행은 집계에서 빠짐
해당되는 행이 하나도 없을 경우
SUM, AVG 함수의 결과는 NULL이 되며, COUNT 함수의 결과는 0

 

- IF

IF(조건, 참일때 값, 거짓일때 )

SELECT IFNULL(column_name, '대체할 값') FROM [table_name]; 

SELECT IFNULL(column_name, IFNULl(column_name, '대체할 값')) FROM [table_name];

SELECT ISNULL(is_discount, 0) AS result

CASE value 혹은 조건 WHEN value1 THEN result1 WHEN value2 THEN result2 … [ELSE else_result] END

 

 

 

 

 

 

- JOIN

INNER - 겹치는 것

LEFT, RIGHT - 한 쪽에만 존재하는 거 + 겹치는 경우 해당 부분만

CROSS - 상호 조인이라고도 불리며, 테이블의 모든 행들과 조인 대상 테이블의 모든 행을
조인시키는 기능이다.

 

- 집합 연산자는 두 개의 SELECT 문의 결과에 대해 합집합, 교집합, 차집합을 구하는 연산자이다.
• 결합하는 SELECT문의 결과는 열의 수나 각각의 데이터형이 똑같아야 한다.
연산자 설명
Table1 UNION Table2 Table1 과 Table2의 합집합
Table1 MINUS Table2 Table1 과 Table2의 차집합
Table1 INTERSECT Table2 Table1 과 Table2의 교집합
* MySQL에는 MINUS, INTERSECT 연산자 지원이 안되고 IN과 NOT IN 연산자로 구현할 수 있다

 

 

- WITH , VIEW 차이

WITH는 단일사용할 쿼리내에 정의되어 있는경우, 해당 쿼리문안에서만 실행된다.

VIEW는 한번 생성하면 DROP할 때까지 계속 존재한다.

 

- VIEW 생성  CREATE VIEW 구문 사용


CREATE VIEW v_orders AS 

SELECT ordered, 0.custid, usrname, O.bookid, saleprice, orderdate
FROM ustomer C, Orders O, Book B
WHERE C.custid = O.custid and B.bookid = O.bookid;

 

DROP VIEW view_name

 

 

- 집계함수
• 값의 합,평균,개수,최대.최소 값에 대한 함수를 "집계함수"라 호칭함


SUM(속성이름) 속성 값들을 합계를 낸다
AVG(속성이름) 속성 값들의 평균을 낸다
COUNT({속성이름] | *}) 속성 혹은 모든 행의 개수를 센다
MAX(속성이름) 속성 값들 중 최대값을 산출한다
MIN(속성이름) 속성 값들 중 최소값을 산출한다
POWER(X, Y) X 값의 Y제곱을 계산한다

 

- 수치형 집계함수

 

ABS(숫자) 숫자 절대값 출력
CEILING(숫자) 숫자보다 크거나 같은 최소 정수 값
FLOOR(숫자) 숫자 값 보다 작은 정수 중 가장 큰 수!  실수는 무조건 버림, 음수일 경우는 제외
ROUND(숫자,자릿수) 숫자를 소수점 이하 자릿수에서 반올림(자릿수는 양수,0,음수)
GREATEST(숫자1,숫자2,...) 주어진 수 중 제일 큰 수 리턴
LEAST(숫자1,숫자2,...) 주어진 수 중 제일 작은 수 리턴

 

- 기간 집계함수
DAYOFYEAR(날짜) 일년을 기준으로 날짜까지의 날짜 수
DAYOFWEEK(날짜) 요일(1: 일~7: 토) 반환
WEEKOFYEAR(날짜) 날짜의 주 수(0~53) 를 반환한다. WEEK(date,3) 호환
YEARWEEK(날짜[, mode]) 주 범위 0~53 를 반환한다. mode(0~7)로 주 지정
MONTHNAME(날짜) 월의 영문(January ~December) 반환
WEEK(날짜[,mode]) 일년 중 몇 번째 주
QUARTER(날짜) 날짜가 4분기 중에서 몇 분기인지를 반환
DATE_FORMAT(날짜,format) dt 속성를 날짜형식 format으로 반환

 

- mode
0 Sunday 0-53 With a Sunday in this year
1 Monday 0-53 With 4 or more days this year
2 Sunday 1-53 With a Sunday in this year
3 Monday 1-53 With 4 or more days this year
4 Sunday 0-53 With 4 or more days this year
5 Monday 0-53 With a Monday in this year
6 Sunday 1-53 With 4 or more days this year
7 Monday 1-53 With a Monday in this year

 

- FORMAT -> 문자열 형태의 소수점 자리수 맞

 

 

- 데이터의 분포에 대한 함수 사용
• STD, STDDEV, VARIANCE 함수
내장함수 설명
STD(expr) expr 의 표준편차를 반환
VARIANCE(expr) expr 의 분산을 반환

 

- 순위 함수

RANK(속성) 공동 순위만큼 건너뜀 (ex: 1,2,2,4,5 ...)
DENSE_RANK(속성) 공동 순위를 뛰어넘지 않음 (ex: 1,2,2,3,4 ...)
ROW_NUMBER(속성) 공동 순위를 무시함 (ex: 1,2,3,4,5 ...)

 

- 순위 함수에 PARTION BY 사용
• 그루핑해서 순위를 매기고자 할 때
SELECT B.bookname, 
ROW_NUMBER () OVER (PARTITION BY O.CUSTID ORDER BY O.SALEPRICE)AS RANKING
FROM BOOK B, ORDERS O
WHERE B.BOOKID=O.BOOKID
GROUP BY 1;

 

- 소계 ROLL UP

말 그대로 소계

GROUPBY ~ WITH ROLLUP

 

- exist 
조건을 만족하는 데이터가 있으면 True. T/F 여부만 확인하여 T인 데이터만 추출

 

use bookstore;

SELECT *
FROM customer;

select mod(9,2) from dual;

SELECT CONCAT(username,':',phone)
FROM customer;

SELECT bookname, ":", publisher FROM book;

SELECT GROUP_CONCAT(username, ":", phone) AS "전화" 
FROM customer;

SELECT substring('abcdef',2,3);

SELECT b1.bookname
FROM Book b1
	 INNER JOIN Book b2 ON b1.publisher = b2.publisher

WHERE b1.price > (SELECT avg(b2.price)
				  FROM Book b2
				  WHERE b2.publisher=b1.publisher);


SELECT username
FROM Customer
WHERE address LIKE '대한민국%'
OR custid IN (SELECT custid FROM Orders);

#25000원 이상 주문한 고개
SELECT c.username
	 , c.address
     , b.bookname
FROM (SELECT custid, bookid, saleprice
	  FROM orders
	  WHERE saleprice >= 25000) o
      INNER JOIN customer c ON o.custid = c.custid
      INNER JOIN book b ON o.bookid = b.bookid;

#도서를 주문하지 않은 고객 id, 이름
SELECT *
FROM customer c
	 LEFT JOIN (SELECT DISTINCT custid 
				FROM orders) o ON o.custid = c.custid
WHERE o.custid IS NULL;

use bookstore;
#Q1. 가격이 가장 싼 책을 구매한 고객의 리스트를 구하시오.
SELECT *
FROM book;

SELECT username
FROM Customer c
	 INNER JOIN Orders o ON c.custid = o.custid
WHERE o.saleprice = (SELECT Max(price) FROM book);

#Q2. 출판사별 판매량 합계와 소계 구하기
SELECT IF(GROUPING(publisher), '소계', IFNULL(publisher,'-'))
	 , sum(saleprice)
FROM book b
	 INNER JOIN Orders o ON b.bookid = o.bookid
GROUP BY publisher WITH ROLLUP;

#Q3. 출판사 및 책이름 합치기
SELECT CONCAT(publisher,':',bookname)
FROM book;

#Q4. 배송 날짜가 주문 날짜 3일 뒤라고 가정할 때, orders 테이블에 deliverydate를 추가하시오.
SELECT *
	 , DATE_ADD(orderdate, INTERVAL 3 DAY) deliverydate
FROM orders;

#Q5. 책을 2권이상 산 고객의 이름과 구매총수량을 나타내시오
SELECT c.username
	 , COUNT(o.custid) cnt
     , sum(saleprice) ts
FROM Orders o
	 INNER JOIN Customer c ON o.custid = c.custid
GROUP BY 1
HAVING cnt >= 2;

#Q6. salesprice를 만원 단위로 집계한다면?

SELECT (FLOOR(saleprice / 10000) * 10000) '1만원 단위'
	 , COUNT(*)
FROM Orders
GROUP BY 1
ORDER BY 1;



# 고객별 총 주문횟수, 총구매액, 평균구매액, 최소/최대구매액 구하기
# 구매하지 않은 고객 포함하기
# 구매하지 않은 고객은 집계 결과 0으로 표현하기
# 총 구매액 순으로 순위 매기기(RANK)
SELECT username AS 고객
	 , IFNULL(COUNT(o.orderid), 0) AS 주문횟수
	 , IFNULL(SUM(o.saleprice), 0) AS 총구매액
     , IFNULL(ROUND(AVG(o.saleprice),1), 0) AS 평균구매액
     , IFNULL(MIN(o.saleprice), 0) AS 최소구매액
     , IFNULL(MAX(o.saleprice), 0) AS 최대구매액
     , RANK() OVER (ORDER BY SUM(o.saleprice) DESC) 순위
     
FROM customer c 
	 LEFT JOIN orders o ON c.custid = o.custid

GROUP BY username
ORDER BY 총구매액 DESC;




#고객별 총 구매 금액에 따라 고갱등급을  나눕니다
#60000보다 크면 최우수 고객
#40000보다 크면 우수 고객
#30000보다 크면 고객
# 등급이아니라 총 구매액에 따른 순위를 매기시오
# 등급이아니라 총 구매액에 따른 순위를 매기시오
SELECT username
	 , CASE
		WHEN sum(saleprice) > 60000 THEN '최우수'
        WHEN sum(saleprice) > 40000 THEN '우수'
        WHEN sum(saleprice) > 30000 THEN '고객'
        ELSE 'ab' 
	   END AS 'ab'
	 , RANK() OVER (ORDER BY sum(saleprice) DESC) 순위
FROM Orders o 
	 INNER JOIN Customer c ON o.custid = c.custid
GROUP BY 1;

##################################################
# 고객별 saleprice 랭킹
##################################################
select c.username
	 , b.bookname
     , o.saleprice
     , RANK() OVER(PARTITION BY username ORDER BY o.saleprice DESC) 순위

from orders o, customer c, book b
where o.custid=c.custid 
and o.bookid=b.bookid;

##################################################
# 지역-도서별 판매 수량
# 지역별 판매수량 소계
##################################################
select substring_index(address,' ',1) as 지역,
       b.bookname as 도서명, 
       count(*) 총판매수량 ,
       sum(o.saleprice) 총판매금액
from customer c, orders o, book b
where c.custid = o.custid
  and o.bookid = b.bookid
group by 1,2 WITH ROLLUP;
# 지역별 총판매금액 소계를 넣고 싶다 -> GROUP BY WITH ROLLUPX

 


💪🏻 좋았던 점, 앞으로 개선해야 할 점 (추가로 배워야 할 점)

 

📌 중간 평가를 대비하기 위해 지금까지 배웠던 내용을 전체적으로 복습했다!

기억 안 나는 부분이 생각보다 많았는데.. 복습을 지속적으로 수행해야 할 필요가 느껴졌다🐿️

 

 

#유데미, #유데미코리아, #유데미부트캠프, #취업부트캠프, #부트캠프후기, #스타터스부트캠프, #데이터시각화 #데이터분석 #태블로

Comments