728x90
반응형

데이터 수집하기


🫐 한국전력거래소 시간별 전력수요량 데이터 수

  • 수집위치 : data.go.kr
  • 한국전력거래소 시간별 전력수요량 csv 파일 다운로드

 

데이터 불러들이기

🫐 데이터 프레임 변수명 : df

  • df = pd.read_csv(file_path)
    → 이렇게 작성하면 UnicodeDecodeError 에러
    → 인코딩 필요
  • pandas는 기본적으로 utf-8
  • 메모장 저장될 때 기본 utf-8, 공공데이터 저장 ansi
  • euc-kr 한국어 타입으로 인코딩
import pandas as pd
file_path = "./01_data/한국전력거래소_시간별 전력수요량_20211231.csv"
df = pd.read_csv(file_path, encoding= "euc-kr")
df

 

🫐 결측데이터 확인

df.info()

 

- 결측치는 없다

 

 

 

 

 

 

 

 

 

 

 

 

 

🫐 이상치 데이터 확인
- 측정된 데이터 이므로 min을 보는게 적절하다
- min이 0 이하로 떨어지면 이상치

df.describe()


🫐 컬럼명의 시간을 데이터화 하기 위하여 컬럼명 추출하기

df.columns

 

🫐 변수로 받기

col_list = df.columns
col_list

 

데이터 프레임 생성하기

 

🫐 3개의 열 (년도, 시간, 전력량)을 가지는 데이터프레임 생성하기

result_df = pd.DataFrame(columns=["년도", "시간", "전력량"])
result_df


🫐데이터프레임에 데이터 행단위 추가하기

  • items() : 튜플로 만들어서 넘겨주면 그 안에 갯수만큼 왼쪽의 변수들이 각각 받아준다.
  • print(ymd, "/", time, "/", value) : 2021-12-31 / 24시 / 70123 까지 추출된다.
  • concat() : 데이터프레임과 데이터프레임을 행단위(axis = 0) 또는 칼럼단위(axis = 1)로 추가할 때 사용
  • ignore_index=True : 행이 추가될 때 행 인덱스 번호를 자동증가 시키기 (default = false)
### 데이터프레임에 데이터 행단위 추가하기
result_df = pd.DataFrame(columns=["년도", "시간", "전력량"])

for index, row in df.iterrows() :
    # print(row)
    ### 년도 데이터
    ymd = row[col_list[0]] # 날짜
    
    ### 시간과 전령량이 합쳐진 데이터
    data = row[col_list[1:]] # 1시 부터 24시 까지. 모든 시간대
    # print(data)

    ### 시간과 전력량을 각각 추출하여 데이터프레임에 넣기
    # - 넣을 값 : 날짜, 시간, 잔력량
    for time, value in data.items() :
        # print(ymd, "/", time, "/", value)

        ### 행단위로 데이터프레임에 추가하기 위해서 추가할 행을 데이터프레임으로 생성
        df_temp = pd.DataFrame({"년도":[ymd], "시간":[time], "전력량":[value]})

        ### 데이터프레임에 행단위로 추가하기
        result_df = pd.concat([result_df, df_temp], axis=0, ignore_index=True)
        
### 최종결과 출력
result_df


       

🫐 정제된 데이터 파일로 저장하기

  • 저장할 경로 지정
  • index=False : 인덱스 번호값은 저장하지 않기(default = True)
save_path = "./01_data/new_data.csv"
result_df.to_csv(save_path, index = False)

좌) index = True 우) index = False 

🫐 저장한 데이터 파일 읽어들이기

file_path = "./01_data/new_data.csv"
df = pd.read_csv(file_path)
df

728x90
반응형
728x90
반응형

판다스(Pandas)

 

    • 행렬 데이터를 처리하기 위한 다양한 함수를 지원하는 라이브러리
    • 파일 읽기, 저장, 행렬데이터 처리, 기본 시각화 등 지원
    • 데이터 전처리 과정에서 주로 사용됨

데이터 분석과정

 

  • 데이터 수집 > 데이터 전처리 > 데이터 가공(필요시 전처리) > 데이터 분석 탐색/시각화(필요시 전처리) > 필요시 모델 훈련(머신러닝 or 딥러닝) > 웹서비스 또는 분석 보고서
  • 책에 나온 일반적인 과정 : 데이터수집 > 전처리 > 분석 > 시각화로 설명되고 있다.
  • 분석과정은 회사에 따라 다르다.

판다스(Pandas) 설치

 

  • Anaconda Prompt에서 pip list로 pandas 설치 확인

  • jupyter notebook에서 import
import pandas as pd
  • 사용되는 데이터 파일 - 노란색 부분

 

컬럼 : 국적코드, 성별, 입국객수, 전년동기

행은 0행 부터 시작한다.

즉, 노란색 부분을 추출하려면 A열에서 C열, 1행에서 7행만 추출한다.

 

 

 

 

 

 

 

데이터 수집 시 확인 사항

 

  • 날짜 확인 : 기준일로 사용
    - 년월일시분이 나타나 있는게 좋다.|
    - 최소한 년월까지는 있어야 한다. 최소 12개의 데이터를 확보할 수 있기 때문이다.
  • 범주형 데이터 확인 : 예로 남자 또는 여자와 같은 데이터
    - 범주형 데이터가 많은 데이터가 좋다. 비교대상이 많아 지기 때문이다.
    - 비교대상이 많아지면 데이터로 보여줄 수 있는게 많아진다

데이터 읽어오기

 

  •  파일 위치 지정
    - 상대경로로 지정한다.
file_path = "./files/sample_1.xlsx"
  • 피일 데이터 추출하기
    - file_path : 파일지정(위치 포함)
    - header : 칼럼명으로 사용할 행의 위치(default - 0)
    - skipfooter : 행의 가장 밑에서부터 포함하지 않을 행의 갯수(default - 0)
    - usecols : 가지고 올 열의 범위(A분터 C까지의 열)(default - data가 있는 모든 열)
sample_1 = pd.read_excel(file_path,
                        header=1,
                        skipfooter=2,
                        usecols="A:C")

 

  • csv, excel, json많이 사용
  • csv는 순수한 text 파일로 처리 과정이 따로 안들어가서 가볍다. 즉, 용량을 더 많이 담을 수 있다.
  • excel 파일 자체에 다양한 처리 과정이 같이 들어가기 때문에 무겁다.

 

 

 

 

 

  • 데이터 조회하기
sample_1

 

  • DataFrame 정보 확인하기
    - DataFrame 타입 : 행렬을 저장 관리하는 타입
    - info()함수는 데이터의 결측치(nan,null) 데이터 확인 가능
    - RangeIndex : 전체 행(row)의 갯수 0 to 5 총 6개
    - 전체 행의 갯수와 각 컬럼의 갯수가 안맞으면 결측 데이터가 존재한다는 의미.
sample_1.info()

 

# Non-Null = not null null이 아닌 데이터의 갯수
#  Dtype = 데이터 타입
#  object 문자열
# int 숫자

0 to 5 총 6개

 

 

 

 

 

  • 데이터프레임 출력
    - 데이터 행/열이 많은 경우 -> 기본 상위 5개, 하위 5개를 추출해서 보여줌
    - 데이터 행/열의 갯수가 작으면 모두 보여줌

  • head() : 상위 데이터 조회
    - 상위 5개
    sample_1.head()​

    - 상위 1개
    sample_1.head(1)​

 

  • tail() : 마지막 데이터 조회
    - default : 5개
    - 하위 5개
    sample_1.tail()​

    - 하위 1개
    sample_1.tail(1)​

  • 기초 통계 데이터
sample_1.describe()

 

- count : 데이터 행의 갯수
- mean : 데이터 평균
- std : 표준편차
- min : 최솟값
- max : 최댓값
- 25%, 50%(중앙값), 75% : 4분위수 데이터
        → 4분위수 데이터를 이용해서 이상치(이상한) 데이터 확인

- 기초통계 데이터는 숫자값을 가지는 컬럼에 대해서만 확인

 

 

 

데이터 조회하기

 

  • key 입력하고 value 받아오기
    - 국적코드 데이터 조회하기
sample_1["국적코드"]

 

- dtype: object

  → 데이터 하나하나의 타입이 object이다.

 

 

 

 

 

 

  • 타입 확인
    - 데이터 전체의 타입
type(sample_1["국적코드"])

 

- Series : 튜플과 모양이 같다. (사용법도 동일)
- {"국적코드" : (데이터, 데이터, ...)}

 

 

 

  • 2차원 행렬 형태로 조회
sample_1[["국적코드"]]

type(sample_1[["국적코드"]])

 

- [[ ]] : 2차원의 행렬인 DataFrame 타입

 

 

 

  • 국적코드와 성별 모두 조회하기
    - 컬럼 2개이상 조회시 [[ ]] 2차원 행렬 형태로 조회해야함
sample_1[["국적코드","성별"]]

 

 

기준년월 컬럼 추가하기

 

  • 2019-11 값을 추가하기
sample_1["기준년월"] = '2019-11'
sample_1

데이터 필터링 하기

 

  • 필터링 : 조건에 맞는 값 조회하기
  • 성별 중에 여성인 데이터만 추출하기
condition = sample_1["성별"] == "여성" 
condition


  • default 값은  True
sample_1[condition == False]


  • 한 줄로 조회하기
sample_1[(sample_1["성별"] == "여성") == True]

 


  • 객체 주소 전달 방식
    - 둘다 같은 곳을 바라 본다
    - sample_1이 바뀌면 sample_2가 바뀌고 sample_2가 바뀌면 sample_1이 바뀜
sample_2 = sample_1

 

  • copy()
    - 메모리 복제방식 (신규로 동일하게 생성 됨)

    - 신규로 만들어진 메모리 주소를 받아옴 (서로 영향 안받음)
    - 주소를 넣는 방식이 아니라 메모리를 복제하는 방식
sample_2 = sample_1.copy()
728x90
반응형
728x90
반응형

📝 문제

더보기

1. 문제설명

 얀에서는 매년 달리기 경주가 열립니다. 해설진들은 선수들이 자기 바로 앞의 선수를 추월할 때 추월한 선수의 이름을 부릅니다. 예를 들어 1등부터 3등까지 "mumu", "soe", "poe" 선수들이 순서대로 달리고 있을 때, 해설진이 "soe"선수를 불렀다면 2등인 "soe" 선수가 1등인 "mumu" 선수를 추월했다는 것입니다. 즉 "soe" 선수가 1등, "mumu" 선수가 2등으로 바뀝니다.선수들의 이름이 1등부터 현재 등수 순서대로 담긴 문자열 배열 players와 해설진이 부른 이름을 담은 문자열 배열 callings가 매개변수로 주어질 때, 경주가 끝났을 때 선수들의 이름을 1등부터 등수 순서대로 배열에 담아 return 하는 solution 함수를 완성해주세요.


2. 제한사항

  • 5 ≤ players의 길이 ≤ 50,000
    - players[i]는 i번째 선수의 이름을 의미합니다.
    - players의 원소들은 알파벳 소문자로만 이루어져 있습니다.
    - players에는 중복된 값이 들어가 있지 않습니다.
    - 3 ≤ players[i]의 길이 ≤ 10

  • 2 ≤ callings의 길이 ≤ 1,000,000
    - callingsplayers의 원소들로만 이루어져 있습니다.
    - 경주 진행중 1등인 선수의 이름은 불리지 않습니다.

3. 입출력 예

players callings result
["mumu", "soe", "poe", "kai", "mine"] ["kai", "kai", "mine", "mine"] ["mumu", "kai", "mine", "soe", "poe"]

4. 입출력 예 설명

  • 입출력 예 #1

 4등인 "kai" 선수가 2번 추월하여 2등이 되고 앞서 3등, 2등인 "poe", "soe" 선수는 4등, 3등이 됩니다. 5등인 "mine" 선수가 2번 추월하여 4등, 3등인 "poe", "soe" 선수가 5등, 4등이 되고 경주가 끝납니다. 1등부터 배열에 담으면 ["mumu", "kai", "mine", "soe", "poe"]이 됩니다.

 

✏️ 작성한 코드

 아래 작성한 코드는 answer를 players와 동일하다고 설정한 뒤 for문을 사용하여 callings와 players를 비교하고 있다. 두 값이 같으면  answer의 현재 인덱스 값이 players의 이전 인덱스 값으로 대체되고, answer의 이전 인덱스 값은 callings의 현재 인덱스 값으로 대체된다.

 입출력 예를 가지고 설명해 보자면, callings[0]인 "kai"와 players[0]인 " mumu" 값이 먼저 비교 되고 값이 같지 않으면 players의 인덱스는 1씩 증가되므로 " mumu", "soe", "poe", "kai", "mine" 순으로 비교 된다. 즉,  callings[0]은 players[3]인 "kai"와 값이 같으므로 이때의 인덱스를 기준으로 answer[3]은 players[3 - 1]인 "poe"로 대체 되고 answer[3-1]인 "poe"는 callings[0]인 "kai"로 바뀌게 되면서 내부 for문이 종료 된다.

 그리고 다시 callings[1]을 players[0]과 비교하면서 for문이 진행된다. 그러나 이렇게 진행할 경우 callings에 해당하는 player를 찾기 위해 반복문을 돌릴때 마다 callings과  players을 비교하게 되므로 효율적이지 못한 코드가 될 수 있다.

class Solution {
    public String[] solution(String[] players, String[] callings) {
        String[] answer = players ;
        for (int i = 0; i < callings.length;i++) {    
            for (int j = 0; j < players.length;j++) {
                if (callings[i].equals(players[j])) {
                 answer[j] = players[j - 1];
                 answer[j - 1] = callings[i];
                 break;
                 }
            }
        }
        return answer;       
    }
}

 

결과는 예시와 같이 나오지만 채점 하면 실행 시간 초과로 오답처리 된다. 아마 이 문제도 HashMap을 써야 하는 것 같다. 

✏️수정한 코드

 HaspMap을 사용해 본 코드이다.

  1.  for (int i = 0; i < players.length;i++) {map.put(players[i], i);}
    → 첫번째 for문으로 map에 players의 값을 저장한다.
  2. for (String name : callings)
    두번째 for문을 사용하면 callings에 있는 배열이 하나씩 name이란 변수에 담기면서 실행이 된다.
  3. int cur = map.get(name);
    먼저 배열의 첫번째 값인 "kai"가 name에 담기고 cur은 map에서의 name의 인덱스 값이 담긴다. 즉, map에 있는 "kai"의 인덱스 값인 3이 cur 값이 된다.
  4. map.put(name, cur - 1); 
    map에 (kai, (3 - 1)) 가 들어간다. 즉, map[2]인 "poe"가 "kai"로 변경된다.
  5. map.put(players[cur - 1], cur);
    map에 ( players[3 - 1] , 3) 이 들어간다. 즉, map[3]인 "kai"가  players[2]인  "poe"로 변경된다.
  6.  players[cur] = players[cur - 1];
     players[cur - 1] = name;
    호출된 플레이어와 이전 위치에 있던 플레이어를 서로 교체하여 플레이어들의 위치를 업데이트한다.
import java.util.*;

class Solution {
    public String[] solution(String[] players, String[] callings) {
        
        HashMap<String,Integer> map = new HashMap<>();
        
        for (int i = 0; i < players.length;i++) {   
            map.put(players[i], i);
        }
        
        for (String name : callings) {
            int cur = map.get(name);
            map.put(name, cur - 1);
            map.put(players[cur - 1], cur);
            players[cur] = players[cur - 1];
            players[cur - 1] = name;
        }
        return players;       
    }
}
728x90
반응형
728x90
반응형

📝문제

더보기

1. 문제 설명

다음은 어느 자동차 대여 회사의 자동차 대여 기록 정보를 담은CAR_RENTAL_COMPANY_RENTAL_HISTORY 테이블입니다. CAR_RENTAL_COMPANY_RENTAL_HISTORY 테이블은 아래와 같은 구조로 되어있으며, HISTORY_ID, CAR_ID, START_DATE, END_DATE는 각각 자동차 대여 기록 ID, 자동차 ID, 대여 시작일, 대여 종료일을 나타냅니다.


Column name Type Nullable 
HISTORY_ID INTEGER FALSE
CAR_ID INTEGER FALSE
START_DATE DATE FALSE
END_DATE DATE FALSE

 


2. 문제

CAR_RENTAL_COMPANY_RENTAL_HISTORY 테이블에서 대여 시작일을 기준으로 2022년 8월부터 2022년 10월까지 총 대여 횟수가 5회 이상인 자동차들에 대해서 해당 기간 동안의 월별 자동차 ID 별 총 대여 횟수(컬럼명: RECORDS) 리스트를 출력하는 SQL문을 작성해주세요. 결과는 월을 기준으로 오름차순 정렬하고, 월이 같다면 자동차 ID를 기준으로 내림차순 정렬해주세요. 특정 월의 총 대여 횟수가 0인 경우에는 결과에서 제외해주세요.


3. 예시

예를 들어 CAR_RENTAL_COMPANY_RENTAL_HISTORY 테이블이 다음과 같다면

HISTORY_ID CAR_ID START_DATE END_DATE
1 1 2022-07-27 2022-08-02
2 1 2022-08-03 2022-08-04
3 2 2022-08-05 2022-08-05
4 2 2022-08-09 2022-08-12
5 3 2022-09-16 2022-10-15
6 1 2022-08-24 2022-08-30
7 3 2022-10-16 2022-10-19
8 1 2022-09-03 2022-09-07
9 1 2022-09-18 2022-09-19
10 2 2022-09-08 2022-09-10
11 2 2022-10-16 2022-10-19
12 1 2022-09-29 2022-10-06
13 2 2022-10-30 2022-11-01
14 2 2022-11-05 2022-11-05
15 3 2022-11-11 2022-11-11

 

대여 시작일을 기준으로 총 대여 횟수가 5회 이상인 자동차는 자동차 ID가 1, 2인 자동차입니다. 월 별 자동차 ID별 총 대여 횟수를 구하고 월 오름차순, 자동차 ID 내림차순으로 정렬하면 다음과 같이 나와야 합니다.

MONTHCAR_IDRECORDS
MONTH CAR_ID RECORDS
8 2 2
8 1 2
9 2 1
9 1 3
10 2 2

✏️작성한 코드

 어려웠던 점은 조건을 줄 때 CAR_ID에 대한 조건을 주고 전체 행에 대한 조건을 따로 줘야 한다는 것이다.  먼저 대여 시작일을 기준으로 2022년 8월 부터 2022년 10월까지 총 대여 횟수가 5회 이상인 자동차들에 대한 조건을 서브쿼리로 준다. 그리고 해당 기간 동안의 월별 CAR_ID 별 총 대여 횟수 리스트를 출력한다.

 작성해놓고 왜 이렇게 적었는지 설명을 못하겠다... 헷

SELECT SUBSTRING(START_DATE,6,2) AS MONTH
		, CAR_ID
    	, COUNT(CAR_ID) AS RECORDS
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
WHERE CAR_ID IN (
    		SELECT CAR_ID 
    			FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY 
   					 WHERE SUBSTRING(START_DATE,1,7) BETWEEN '2022-08' AND '2022-10'
    		GROUP BY CAR_ID
    		HAVING COUNT(CAR_ID) >= 5)
	AND SUBSTRING(START_DATE,1,7) BETWEEN '2022-08' AND '2022-10'
GROUP BY SUBSTRING(START_DATE,6,2), CAR_ID
ORDER BY MONTH, CAR_ID DESC;

 

코드 실행 시 아래와 같은 형식으로 데이터가 출력된다.

728x90
반응형
728x90
반응형

🎄사용자  정의 함수

  • 상품테이블에서 아래 컬럼 조회하기
    - 서브쿼리 사용 (join 사용하지 않기)
    - 조회컬럼 : 상품명, 상품분류명, 상품분류코드
 SELECT prod_name
 	, (select lprod_nm FROM lprod WHERE lprod_gu = prod_lgu) AS lprod_nm
    	, prod_lgu
 FROM prod;

 

  • 상품분류명을 추출하는 함수 생성하기
    - IF문으로 NULL값 있는지 확인
    - Delimiter 뒤에는 무조건 띄어쓰기
    - 문자열이 맞지 않아서 CHARACTER SET UTF8MB4 적용
 -- 함수 구문 시작
Delimiter //

-- 사용자 정의함수
CREATE FUNCTION udfGetLprodNm(paramGu VARCHAR(10))

-- 리턴타입 정의
RETURNS VARCHAR(50) CHARACTER SET UTF8MB4

-- 함수 기능 시작
BEGIN
	
	-- 반환할 값을 저장할 변수 선언
	DECLARE result VARCHAR(50) CHARACTER SET UTF8MB4;

	-- 상품분류명을 추출하는 sql구문 작성
	SELECT lprod_nm INTO result
	FROM lprod
	WHERE lprod_gu = paramGu;
	
	-- 조회결과가 있는지 확인
	if result IS NULL then
	 SET result = 'null';
	END if;
	
	-- 반환하기
	RETURN result;
    
-- 함수 기능 종료
END //

-- 함수 전체 구문 종료
Delimiter ;

  •  생성한 함수 호출하여 처리하기
SELECT prod_name
	,defGetLprodNm(prod_lgu) AS lprod_nm
    	,prod_lgu
FROM prod;

 

위에서 서브쿼리를 사용하여 작성한 코드와 동일한 결과

찾은 행 74 개

 

 

 

 

 

 

 

 

 

사용자 함수 정의 문제

문제 1

  • 회원이름, 성별 조회하기
  • 성별은 남성, 여성으로 조회
  • 함수 이름 : udfGetMenWomen
  • udfGetMenWomen 함수 정의
    - 남성 / 여성 추출하기
Delimiter //

CREATE FUNCTION udfGetMenWomen(paramNum INT)

-- 리턴 타입 정의
RETURNS VARCHAR(4) CHARACTER SET UTF8
BEGIN
	-- 반환할 변수 선언
	DECLARE result VARCHAR(4) CHARACTER SET UTF8;
	
	-- 남여 구분을 위한 조건문 처리
	if MOD(SUBSTRING(paramNum, 1, 1), 2) = 0 THEN
		SET result = '여성';
	ELSE 
		SET result = '남성';
	END if;

	RETURN result;
	
END //

Delimiter ;

 

 

  • 생성한 함수 호출하여 처리하기
SELECT mem_name
, udfGetMenWomen(mem_regno2) AS gender
FROM member;


문제 2

  • 새로운 주문이 발생했을 때 신규주문번호를 발급하는 함수 생성하기
  • 함수이름 : udfGetNewCartNo()
  • udfGetNewCartNo 함수 정의
Delimiter //

CREATE FUNCTION udfGetNewCartNo(paramNum VARCHAR(50))

RETURNS VARCHAR(50) CHARACTER SET UTF8

BEGIN
	DECLARE result VARCHAR(50) CHARACTER SET UTF8;
	
	if SUBSTRING(paramNum,1,8) = CURDATE() then	
		set result = paramNum + 1;
	ELSE
		SET result = concat(DATE_FORMAT(CURDATE(),'%Y%m%d'),'00001');
	END if;
	
	RETURN result;

END //

Delimiter ;

 

  • 생성한 함수 호출하여 처리하기
SELECT udfGetNewCartNo(MAX(cart_no)) AS newnum
FROM cart;

 



  • udfGetNewCartNo 함수 정의 - 강사님 
--
Delimiter //

CREATE FUNCTION udfGetNewCartNo()

RETURNS VARCHAR(13) CHARACTER SET UTF8

BEGIN
	DECLARE result VARCHAR(13) CHARACTER SET UTF8;
	
	SELECT if (MAX(cart_no) IS NOT NULL,
					MAX(cart_no) + 1,
						CONCAT(replace(CURDATE(), '-', ''),
								'00001')) INTO result
													
	FROM cart
	WHERE SUBSTRING(cart_no, 1, 8) = CURDATE();
	
	RETURN result;

END //

Delimiter ;

 

  • 생성한 함수 호출하여 처리하기 - 강사님
SELECT udfGetNewCartNo();

🎄View

  •  VIEW : 가상테이블
  • 자주 사용되거나, SQL 구문이 긴 경우 조회 목적으로만 사용
  • 미리 객체화 시켜서 테이블 처럼 사용하는 방식
  • 조회만 가능하며, 입력/수정/삭제가 되지 않는다.
  • 입력/수정/삭제가 되는 경우도 있지만, VIEW 사용 목적에 맞지 않는다.
  • 구매 내역이 없는 회원 조회하기
    - 조회 컬럼 : 회원아이디, 회원이름
SELECT mem_id, mem_name
FROM member
WHERE mem_id NOT in (SELECT cart_member FROM cart);

  • 구매내역이 없는 회원 view 생성
Delimiter //

CREATE VIEW viewNoCartMember AS

-- 조회할 select문 생성
SELECT mem_id, mem_name
FROM member
WHERE mem_id NOT in (SELECT cart_member 
FROM cart)//

Delimiter ;
  • view 사용하기
    - 사용법 : 테이블과 동일
SELECT *
from viewNoCartMember;

🎄저장 프로시저(Stored Procedure; sp)

  • 프로그램 영역이 아닌, DB자체에서 SQL구문을 관리하고자 할 때 사용
  • 데이터베이스에 SQL구문을 객체화하여 호출방식으로만 사용하는 방식

  • 구매내역이 없는 회원 프로시저 생성
Delimiter //

CREATE Procedure spNoCartMember()
Begin

-- 조회할 select문 생성
SELECT mem_id, mem_name
FROM member
WHERE mem_id NOT in (SELECT cart_member 
FROM cart);

END //
Delimiter ;
  • 프로시저 호출하기
call spNoCartMember();

 

VIEW / 저장 프로시저 문제

문제 1

  • 모든 거래처별 매출 금액의 총합 조회하기
  • 단, 2005년도 주문내역
  • 조회컬럼 : 거래처 코드, 거래처명, 매출금액의 총합
  • 위 조회에 대한 select문을 view로 생성
  • 프로시저에서 위에 생성한 view를 사용하여 call
  • view이름 : viewGetBuyerAll
  • 프로시저이름 : spGetBuyerAll

  • viewGetBuyerAll VIEW 생성
Delimiter //

CREATE VIEW viewGetBuyerAll AS

	-- 조회할 select문 생성
	SELECT buyer_id
			, buyer_name
			, SUM(NVL(prod_sale*cart_qty,0)) AS total
	FROM buyer
		LEFT JOIN prod
			ON (buyer_id = prod_buyer)
		LEFT JOIN CART
			ON (prod_id = cart_prod 
					AND cart_no LIKE '2005%')
	GROUP BY buyer_id, buyer_name//

Delimiter ;

 

  • spGetBuyerAll 프로시저 생성
Delimiter //

CREATE procedure spGetBuyerAll()
begin

	-- 조회할 select문 생성
	SELECT buyer_id
			, buyer_name
			, SUM(NVL(prod_sale*cart_qty,0)) AS total
	FROM buyer
		LEFT JOIN prod
			ON (buyer_id = prod_buyer)
		LEFT JOIN CART
			ON (prod_id = cart_prod 
					AND cart_no LIKE '2005%')
	GROUP BY buyer_id, buyer_name;
	
END //	

Delimiter ;

 

  • VIEW / 프로시저 호출
SELECT *
FROM viewgetbuyerall;

CALL spGetBuyerAll();

 

 

🎄저장 모듈(Stored Module)

  •  SQL 문장을 데이터베이스 서버에 저장하여 사용자와 애플리케이션 사이에서 공유할 수 있도록 만든 일종의 SQL 컴포넌트 프로그램이며, 독립적으로 실행되거나 다른 프로그램으로 부터 실행될 수 있는 완전한 실행 프로그램이다. Oracle의 저장 모듈에는 Procedure, User Defined Function, Trigger가 있다.

  • Procedure와 Trigger의 차이점
Procedure Trigger
CREATE Proceduer 문법사용 CREATE Trigger 문법사용
EXECUTE 명령어로 실행 생성 후 자동으로 실행
COMMIT, ROLLBACK 실행 가능 COMMIT, ROLLBACK 실행 안됨

 

728x90
반응형
728x90
반응형

🎀 Union / Union All

Union

  • 조회결과와 조회결과를 행단위로 합치는 기능
  • 조회결과들 간의 칼럼의 개수는 동일해야 함
  • 조회결과들 간의 데이터 타입을 동일해야 함
  • 예시
    - 'member' 'cart'는 구분자로 쓰임
SELECT 'member', mem_id, mem_name
FROM member
UNION
SELECT 'cart', cart_member, cart_prod
FROM cart;

 

찾은 행  28개

 

 

 

 

 

 

 

 

 

UNION ALL

  • 회원 28명, 주문정보 135건 일 때 아래 코드 실행 시 결과
    UNION : 155건
    UNION ALL : 163건
SELECT 'member', mem_id, mem_name
FROM member
UNION all
SELECT 'cart', cart_member, cart_prod
FROM cart;
  • UNION : 중복제거
  • UNION ALL : 중복포함
  • MINUS : 차집합
  • INTERSECT : 교집합

Union 문제

문제 1 - 1번

SELECT mem_id, mem_name, SUM(nvl(cart_qty*prod_sale,0)) AS total
FROM member 
			left join cart
				ON (mem_id = cart_member)
			left JOIN prod
				ON (cart_prod = prod_id)
GROUP BY mem_id
UNION
SELECT '', '', SUM(nvl(cart_qty*prod_sale,0)) AS total
FROM member 
			left join cart
				ON (mem_id = cart_member)
			left JOIN prod
				ON (cart_prod = prod_id)
GROUP BY '', '';

 

찾은 행 29개

- 그룹화 하지 않은 SUM은 전체 행의 합이 구해진다.

- Group by ' ', ' ' 는 아무 의미가 없지만 빈 문자열로 컬럼을 지정하면 오류가 나기 때문에 문법상 적어준 것이다.

 

 

 

 

 

 

 

 


문제 1 - 2번

  • Union 문제 1 - 1번 에서 총 구매금액 순을 내림차순으로 정렬
  • 단, 총 구매금액의 총합은 마지막 행에 위치
SELECT A.mem_id, A.mem_name, A.total
FROM 
(SELECT mem_id, mem_name, SUM(nvl(cart_qty*prod_sale,0)) AS total
FROM member 
			left join cart
				ON (mem_id = cart_member)
			left JOIN prod
				ON (cart_prod = prod_id)
GROUP BY mem_id
ORDER BY total DESC) A
UNION
SELECT '', '', SUM(nvl(cart_qty*prod_sale,0)) AS total
FROM member 
			left join cart
				ON (mem_id = cart_member)
			left JOIN prod
				ON (cart_prod = prod_id)
GROUP BY '', '';

 

 

 

 

 

 

 

 

 

 

 

 

 

🎀 Exists / Not Exists

Exists

  • 조회결과가 1건이라도 있으면 true, 0건이면 false
  • 서브쿼리를 적용(다중컬럼의 다중행 모두 가능)
  • 예시
    - 구매내역이 있는 회원만 조회
    - 아래 쿼리 실행시 회원 28명 중 19명이 조회 된다.

    SELECT mem_id, mem_name
    FROM member
    WHERE EXISTS(SELECT *
    FROM cart
    WHERE cart_member = mem_id);​

Not Exists

  • 예시
    -
    구매 (주문) 내역이 없는 회원만 조회
    - 아래 쿼리 실행시 회원 28명 중 9명이 조회 된다.
SELECT mem_id, mem_name
FROM member
WHERE NOT EXISTS (SELECT * FROM cart WHERE mem_id = cart_member);

 

Exists / Not Exists 문제

문제 1번

  • 2005년도 구매내역이 있는 회원 조회하기
  • 단, 구매내역이 있는 회원의 총구매금액이 3천만원 이상인 데이터에 대해서만 조회
  • 조회컬럼 : 회원아이디, 회원이름, 마일리지
  • 방법 1 - Exists 사용
SELECT mem_id, mem_name, mem_mileage
FROM member
WHERE EXISTS (
		SELECT SUM(cart_qty*prod_sale)
			FROM cart, prod
			WHERE cart_member = mem_id
				AND cart_prod = prod_id
				AND left(cart_no,4) = '2005'
		HAVING SUM(cart_qty*prod_sale) >= 30000000);
  • 방법 2 - Inline View 사용
SELECT A.mem_id, A.mem_name, A.mem_mileage
FROM(
	SELECT mem_id, mem_name, mem_mileage, SUM(nvl(cart_qty*prod_sale,0)) AS total
		FROM member 
        	LEFT JOIN cart
				ON ( mem_id = cart_member AND left(cart_no,4) = '2005')
			LEFT JOIN prod
				ON(cart_prod = prod_id)
		GROUP BY mem_id) A
WHERE A.total >= 30000000;

 

결과는 동일하다.

 

 

 

🎀 UPDATE

  • 데이터 수정하기
  • UPDATE 할 땐 수정하려는 값이 문제에서 제시한 수정 대상이 맞는지  SELECT ~ WHERE 절로 확인하기
  • 수정 및 삭제 시 기준 컬럼은 PK값을 기준으로 행을 조건 처리 해야 함
  • 예시 1
    - 회원아이디 a001, b001인 회원의 마일리지 값을 2로 수정
UPDATE member set mem_mileage = 2
WHERE mem_id IN ('a001','b001') ;
  • 예시 2
    - 구매내역이 있는 회원의 마일리지 값을 3으로 일괄 수정처리하기
UPDATE member SET mem_mileage =3
WHERE EXISTS(SELECT *
FROM cart
WHERE cart_member = mem_id);

 

UPDATE 문제

문제 1

  • Exists 문제 1번 조건에 만족하는 회원에 대해서 마일리지 값을 1000점 부여하기
  • 방법 1 - Exists 사용
UPDATE member SET mem_mileage = 1000
WHERE EXISTS (
			SELECT SUM(cart_qty*prod_sale)
				FROM cart, prod
					WHERE cart_member = mem_id
						AND cart_prod = prod_id
						AND left(cart_no,4) = '2005'
					HAVING SUM(cart_qty*prod_sale) >= 30000000);
  • 방법 2 - Inline View 사용
UPDATE member SET mem_mileage = (mem_mileage + 1000)
	WHERE mem_id IN(
		SELECT A.mem_id
		FROM (
			SELECT mem_id, mem_name, mem_mileage, SUM(nvl(cart_qty*prod_sale,0)) AS total
			FROM member 
				LEFT JOIN cart
					ON ( mem_id = cart_member AND left(cart_no,4) = '2005')
				LEFT JOIN prod
					ON(cart_prod = prod_id)
			GROUP BY mem_id) A
	WHERE A.total >= 30000000);
728x90
반응형

+ Recent posts