|  Exerd를 사용해 설계해보기

- 부트캠프 실습 후 간단하게 배운 내용을 복습하고자 사용법만 간략히 정리하려고 한다.

* 참고로 Exerd를 설치하는 방법은 이전 포스팅에서 다루었다.

1. 도구 설명

no 설명 비고
0 Logical / Physical 토글 버튼  
1 테이블 생성 칼럼 추가 : [Alt] + [Enter]
2 - 점선 : 비식별 관계  >> pk를 추가하여 연결
- 실선 : 식별 관계      >> fk로 추가하여 연결
 
3 마우스 우측 클릭 후, [논리/물리 같이 보기] 버튼 터치하면 함께 보기 가능  
4 도메인 및 데이터 타입 등에 대한 설명 보기  

 

2. 데이터 타입 및 제약 조건 지정하기

(1) 하단의 데이터 타입 끌어오기

- 하단에 보면 샘플로 만들어진 데이터타입이 이미 있는데 이걸 끌어오는 방법

 

(2) 하나씩 직접 입력하는 법

- 테이블의 칼럼을 더블클릭하면 데이터 타입을 직접 입력할 수 있다.

 

(3) 테이블 전체 칼럼 입력하는 법

- 테이블을 선택하고, 우측마우스 - [특정(속성)] - [칼럼] 을 누르면 아래와 같이 창이 나온다.

- 여기에서 전체적으로 작성이 가능하며, [일반] 탭의 "자동 증가" 박스를 체크하면 auto-increment가 된다.

 

3. DDL로 변환하기

- 좌측 또는 우측에 나와있을 [모델]에서 Schema명을 수정하고, 테이블도 논리/물리 모두 잘 작성했다면

- [Help] - [eXERD] - [포워드 엔지니어링] 을 통해 DDL로 변환한다.

* "이름 앞에 스키마 표시"를 하게 되면 명령어를 제대로 인식을 못하므로 비체크 후 [Next]

- 변환된 DDL 결과물을 클립보드로 복사해서 DataGrip이나 DBeaver와 같은 DB툴에서 사용할 수 있다.

 

[ 참고 및 출처 ]

부트캠프 수업을 들은 후 정리한 내용입니다.

|  모델링이란?

- 모델링이란? 비즈니스 목적에 맞게 현실세계의 데이터를 도식화하는 것 

- 왜 모델링을 하는가? 비즈니스 목적에 부합하면서도, 효율적인 자원 관리를 하기 위해

- 모델링의 특징

추상화 현실 세계의 실재를 도식화 하는 과정
단순화 현실 세계의 현상을 약속된 규약에 의해 제한된 표기법 및 언어로 쉽게 표현하는 과정
명확화 모두가 이해할 수 있도록 모호함을 제거하고 정확하게 현상을 기술하는 과정

- 모델링을 바라보는 다른 시각

모델링 데이터  업무의 내용 (무엇을 - Data).

- 요구사항 X는 어떤 데이터와 연관되는가?
프로세스  업무의 처리 (어떻게 - Process).

- 요구사항 X와 연관된 기존 시스템은 뭔가?
- 요구사항 X를 위한 전반적인 프로세스는 뭔가? 
상관 관계 데이터와 프로세스간의 관계

- 업무 처리 방법(프로세스)에 따라 데이터는 어떻게 영향을 받는가?

 

|  데이터 모델링

- 데이터의 모델링이란? 정보시스템을 구축하기 위한 데이터 기반 업무 분석 기법

- 데이터 모델링 3단계

출처:https://blog.naver.com/PostView.nhn?blogId=qbxlvnf11&logNo=221225469375

단계 개념적 데이터 모델링(Conceptual) 논리적 데이터 모델링(Logical) 물리적 데이터 모델링(Physical)
정의 현실세계의 실재를 높은 추상화
수준으로 형성화하는 과정
비즈니스 정보의 논리적인 구조와
규칙을 명확하게 표현하는 과정
실제 DBMS에 데이터를 어떻게
저장할지 정의하는 과정
하는일 엔터티 및 엔터티간 관계 파악 트랜잭션 인터페이스 설계,
정규화, 참조 무결성 규칙 정의,
M:M관계 해소 등
트랜잭션 세부사항을 설계,
물리적 저장 구조(db,table..),
자료 추출 접근 방법 등을 정함

* 트랜잭션 : 쪼갤 수 없는 업무의 최소 단위 (ex. 물건을 산다)

* 일반적으로 개념적 모델링과 논리적 모델링을 함께 진행하는 경우가 많다고 한다.

 

|  데이터 모델링 표기법

- 다양한 표기법이 있지만 크게 아래와 같이 두 가지 방법에 대해서 많이 사용된다고 한다. 

피터첸 표기법 (E-R Entity-relationship Model) - Entity : 사각형
- Relationship : 마름모
- Attribute : 타원형
IE/Crow's Foot 표기법 Erwin에서 보는 발톱모양의 관계선에 해당

더보기

[ ER WIN 프로그램에서 쓰는 표기법에 대한 상세 설명 ]

* 출처 : https://lipcoder.tistory.com/330

- 그 중 피터첸 곧, E-R모델이 가장 많이 사용된다고 하는데, 자세한 내용은 아래와 같다.

피터첸_예시__출처:https://lipcoder.tistory.com/330

Entity 객체, 실체 사람, 장소, 물건, 사건, 개념 등의 명사

1) 업무와 연관되며 관리가 필요한 정보
2) 유일한 식별자에 의해 식별이 되어야
3) 두 개 이상의 영속적으로 존재하는 인스턴스의 집합이어야한다.
..... 등을 고려하는 것이 필요하다. (자세한 사항은 생략)
ex. 고객
Attribute 속성 더 이상 분리되지 않는 최소의 데이터 단위

* 도메인 : 각 속성이 가질 수 있는 값의 범위
  (ex. 성별 : 남자, 여자, 기타)
ex.
고객번호, 성명, 주소
Relationship 관계 상호 관계

- 관계명 ) 관계 시작점과 관계 끝 점이 있다.
- 관계 차수 ) 1 : 1, 1 : M, M : M(Many)
- 관계 선택 사양 ) 필수, 선택
ex.
고객 - 주문하다 - 주문서

 

|  데이터 모델링 프로그램

- ER WIN, ER Studio, eXERD 등 데이터 모델링을 위한 다양한 툴이 있다.

- 그 중에서도 IT업계에서는 ER WIN을 가장 많이 사용한다고 한다.

* ER WIN 다운로드 및 설치 안내 바로가기

* 이클립스 Exerd 플러그인 설치 (더보기)

더보기

[1] Exerd 홈페이지에서 이클립스 플러그인 버전을 선택하면 URL이 제공된다.

    http://exerd.com/update/exerd/3.x/

[2] 이클립스에서 [help]-[install software]를 선택한 후 [Add]를 통해 URL를 입력

 

 

[ 참고 및 출처 ]

부트 캠트 수업을 들은 후 정리한 내용입니다.

데이터모델링 표기법 https://lipcoder.tistory.com/330

https://blog.naver.com/PostView.nhn?blogId=qbxlvnf11&logNo=221225469375 

https://www.sap.com/korea/insights/what-is-data-modeling.html

https://chrismare.tistory.com/entry/ERwin-%EB%8B%A4%EC%9A%B4%EB%A1%9C%EB%93%9C-%EB%B0%8F-%EC%84%A4%EC%B9%98

|  동적계획법이란?

- 복잡한 문제를 여러 개의 간단한 문제로 분리하여 해결하는 방법

- 원리 및 구현 방법

1) 큰 문제를 부분적으로 분리하여 분석한다

--> 부분적인 문제의 결과값은 항상 동일해야한다.

2) 1)을 통해 알게된 규칙을 통해 점화식을 생성한다.

3) 기존 배열과 dp배열을 어떻게 만들지 구상하고

4) 아래 두 가지 방법 중 적절한 구현 방법에 따라 수도 코드를 작성한다. 

타뷸레이션 = 바텀-업 - for문을 사용하여 구현
메모이제이션 = 탑-다운

* 이미지 출처 : 나무위키


- 재귀를 사용하여 구현

 

|  피보나치를 통해 보는 동적 계획법

- 점화식을 통해 재귀로 푼 피보나치 문제 풀이는 아래와 같았다.

// 피보나치 수열
// 재귀 (일반풀이 방법) - O(n^2), 계산했던 부분도 다시 계산
int fibonachi(int n) {
    if (n < 2) {
        return n;
    } else {
        return fib(n - 2) + fib(n - 1);
    }
}

- 타뷸레이션 방식으로 이를 풀게 되면, 1 1 2 3 5 8.. 순으로 데이터를 넣고 조회한다.

// 타뷸레이션 방식 - O(n)
int fibo2(int n) {
	// 재활용할 메모리 공간
    int[] dp = new int[n + 1];
    dp[0] = 1;
    dp[1] = 1;
    
    for (int i = 1; i <= n; i++){
    	dp[i] = dp[i - 2] + dep[i - 1];
    }
    
    return dp[n];
}

- 메모이제이션을 사용하게 되면, Top-down 방식으로 재귀를 호출하는데,

  첫번째 방식과의 차이는 이미 확인한 데이터는 다시 하위로 깊이를 내려가 풀이 하지 않는다는 것이 다르다.

// 메모이제이션 방식 - O(n)
int[] dp = new int[8];
int fibo2(int n) {

    if (n <= 2) {
    	return 1;
    } 
    
    if (dp[n] != 0) {
    	return dp[n];
    }
    
    dp[n] = fibo2(n - 2) + fibo2(n - 1);
    
    return dp[n];
}

 

|  백준 문제풀이

1 1로 만들기 https://www.acmicpc.net/problem/1463
2 퇴사 https://www.acmicpc.net/problem/14501
3 이친수 구하기 https://www.acmicpc.net/problem/2193
4 2*N 타일 구하기 https://www.acmicpc.net/problem/11726
5 쉬운 계단 수 https://www.acmicpc.net/problem/10844
6 연속된 정수의 합 구하기 https://www.acmicpc.net/problem/13398
7 최장 공통 부분 수열 찾기    
8 가장 큰 정사각형 찾기    
9 빌딩 순서 구하기    
10 DDR을 해보자    
11 행렬 곱 연산 횟수의 최솟값 구하기    
12 외판원의 순회 경로 짜기    
13 가장 길게 증가하는 부분 수열 찾기    
더보기

1. 1로 만들기

- 양의 정수 1~N까지를 아래의 점화식에 따라 풀이한 문제

D[i] = D[i - 1] + 1
if (2의 배수) D[i / 2] + 1이 D[i]보다 작으면 변경
if (3의 배수) D[i / 3] + 1이 D[i]보다 작으면 변경
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Ex1463 {
    public static void main(String[] args) throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        // N : 구하고자 하는 수
        int N = Integer.parseInt(br.readLine());
        int[] dp = new int[N + 1];
        dp[1] = 0;

        // * 규칙이 반복되는 구간은 2부터
        // for (i : 2 ~ N) {
        //    D[i] = D[i - 1] + 1 // 1을 뺀 점화시
        //    if (2의 배수) D[i / 2] + 1이 D[i]보다 작으면 변경
        //    if (3의 배수) D[i / 3] + 1이 D[i]보다 작으면 변경
        // } 
        for (int i = 2; i <= N; i++) {
            dp[i] = dp[i - 1] + 1;

            if (i % 2 == 0) {
                dp[i] = Math.min(dp[i], dp[i / 2] + 1);
            }

            if (i % 3 == 0) {
                dp[i] = Math.min(dp[i], dp[i / 3] + 1);
            }
        }

        // 출력
        System.out.println(dp[N]);
    }
}

 

2. 퇴사

- dp에서 자주 나온다는 배낭 문제와 약간 비슷하나 다른 문제였다.

- 일련의 스케줄이 주어지고 기간 제약을 고려하여 최대 수익을 내는 문제

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Ex14501 {
    public static void main(String[] args) throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        // N 개의 스케줄을 각각의 일차원 배열에 받는다.
        int N = Integer.parseInt(br.readLine());

        // D 점화식 배열
        int[] D = new int[N + 2];

        // T 기간 배열
        int[] T = new int[N + 1];

        // P 수입 배열
        int[] P = new int[N + 1];

        for (int i = 1; i <= N; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine());

            T[i] = Integer.parseInt(st.nextToken());
            P[i] = Integer.parseInt(st.nextToken());
        }

        // 터뷸레이션을 사용해서 D를 구한다.
        // D[i] = i날짜부터 n+1(퇴사일)까지 벌수 있는 최대 수익
        // for (i : N ~ 1){
        //    if (i+T[i]가 퇴사일보다 크면) D[i] = D[i + 1]
        //    if (i+T[i]가 퇴사일보다 크지 않으면) D[i] = Math.max(D[i + 1], P[i] + D[i + T[i]])
        // }
        for (int i = N; i >= 1; i--) {
            if (i + T[i] > N + 1) {
                D[i] = D[i + 1];
            } else {
                D[i] = Math.max(D[i + 1], D[i + T[i]] + P[i]);
            }
        }

        // 출력
        // D[1]
        System.out.println(D[1]);
    }
}

 

3. 이친수 구하기

- 욕 같지만 이진수를 만드는 특정 규칙를 지킨 수의 갯수를 구하는 문제였다.

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Ex2193 {
    public static void main(String[] args) throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        int N = Integer.parseInt(br.readLine());

        // D 배열을 만든다 (2차원 배열)
        // dp[1][0] = 0, dp[1][1] = 1 초기화
        long[][] dp = new long[N + 1][2];
        dp[1][0] = 0;
        dp[1][1] = 1;

        // for (i : 2 ~ N) {
        //    dp[i][0] = dp[i - 1][0] + dp[i - 1][1] // 0은 0이나 1 뒤에 붙일 수 있다.
        //    dp[i][1] = dp[i - 1][0] // 1은 0 뒤에만 붙일 수 있다.
        // }
        for (int i = 2; i <= N; i++) {
            dp[i][0] = dp[i - 1][0] + dp[i - 1][1];
            dp[i][1] = dp[i - 1][0];
        }

        System.out.println(dp[N][0] + dp[N][1]);
    }
}

 

... 나머지는 더 풀이를 하고 모르는 부분만 정리하여 올리려 한다.

위의 내용은 스스로 정리한 부분에 대해 이해할 수 있게 문제풀이한 것을 올린 내용..

 

[ 출처 및 참조 ]

- 부트 캠프 강의를 들은 후 정리한 내용입니다.

- [Do it! 알고리즘 코딩 테스트 - 자바 편] 

'Computer Science > Algorithm' 카테고리의 다른 글

[알고리즘] 최단 경로 구하기 - 1. 다익스트라  (0) 2022.09.01
[알고리즘] 백트래킹  (0) 2022.08.31
모듈러 산술  (0) 2022.08.25
[알고리즘] 분할정복  (0) 2022.08.25
[알고리즘] 그리디  (0) 2022.08.25

|  모듈러 산술

- 모듈러 (=mod = %)는 덧셈, 뺄셈, 곱셈에 있어서 아래와 같은 산술을 할 수 있는 특징이 있다.

- 알고리즘 문제를 풀다보면 애매하게 정수 Max값을 넘을랑 말랑 하는 데이터가 있기도 한데,

  그럴 때 이 모듈러 산술을 고려해서 문제를 풀면 굳이 Long 타입 변수를 쓰지 않아도 Int만으로 충분히 풀이가 가능하다.

(a + b) % C = (a % C + b % C) % C
(a - b) % C = (a % C - b % C) % C
(a * b) % C = (a % C * b % C) % C

 

|  참고할 만한 문제

https://www.acmicpc.net/problem/11726

 

11726번: 2×n 타일링

2×n 크기의 직사각형을 1×2, 2×1 타일로 채우는 방법의 수를 구하는 프로그램을 작성하시오. 아래 그림은 2×5 크기의 직사각형을 채운 한 가지 방법의 예이다.

www.acmicpc.net

 

 

[ 참고 ]

https://developer-mac.tistory.com/84

https://sskl660.tistory.com/75

'Computer Science > Algorithm' 카테고리의 다른 글

[알고리즘] 백트래킹  (0) 2022.08.31
[알고리즘] DP (동적 계획법)  (0) 2022.08.26
[알고리즘] 분할정복  (0) 2022.08.25
[알고리즘] 그리디  (0) 2022.08.25
[알고리즘] 탐색 - DFS, BFS, 이진 탐색  (0) 2022.08.25

|  분할정복이란?

- 폰노이만 구조를 만든 그 폰노이만에 의해 소개된 알고리즘

- 간략하게 말하면, 큰 문제를 작은 단위로 쪼갠 후 다시 조합하여 문제를 해결하는 방법을 말한다.

분할: 문제를 더이상 분할할 수 없을 때까지 동일한 유형의 여러 하위 문제로 나눈다.
정복: 가장 작은 단위의 하위 문제를 해결하여 정복한다.
조합: 하위 문제에 대한 결과를 원래 문제에 대한 결과로 조합한다

*출처 : 나무위키

 

|  분할정복 과정

1. 문제를 하나 이상의 작은 단위로 분할

2. 작은 단위에서 부분적인 해결

3. 부분들의 해결을 조합해 전체 문제의 해답을 찾는다.

function F(x):
  if F(x)가 간단 then:
    return F(x)를 계산한 값
  else:
    x 를 x1, x2로 분할
    F(x1)과 F(x2)를 호출
    return F(x1), F(x2)로 F(x)를 구한 값
    
* 출처 : 나무위키

 

|  장단점

장점 어려운 문제를 해결할 수 있다
병렬적으로 문제를 해결하는데에 이점이 있다.
단점 메모리 사용량이 높다(재귀 호출을 통한 오버헤드 발생)

 

|  예시

분할정복의 예시로 자주 거론되는 것으로 아래 네 가지가 있다. 

이 중에서 내 단계에서 언급하기 쉬워 보이는 1~3의 알고리즘만 적어보려고 한다.

1. 합병 정렬

2. 퀵소트

3. 카라추바 알고리즘

4. 고속 푸리에 변환

 

1. 합병정렬

- 분할정복과 투포인터의 특성을 사용해서 만들어진 정렬이라 볼 수 있을 것 같다.

- 1) 먼저 배열의 범위를 투 포인터를 통해 분할하여 지정한 후에,

- 2) 작은 범위에서 데이터를 비교하여 정렬을 하고

- 3) 작은 범위를 조합하여 전체 정렬을 이루는 과정 

void mergeSort(int[] arr, int[] tmp, int left, int right){
	if (left < right) {
    	int mid = (left + right) / 2;
        // mid를 기준으로 배열을 분할한다.
        mergeSort(arr, tmp, left, mid);
        mergeSort(arr, tmp, mid + 1, right);
        // mid를 기준으로 배열을 조합한다.
        merge(arr, tmp, left, right, mid);
    }
}

void merge(int[] arr, int[] tmp, int left, int right, int mid){
    // mid를 기준으로 좌/우 포인터, 
    // index포인터를 준비하고
    int l = left;
    int r = mid + 1; 
    int idx = left;
    
    // 좌/우 포인터를 비교하여 tmp에 오름차순으로 저장
    // 적어도 두 포인터 중 하나가 범위 내에 있을 때에
    while (l <= mid || r <= right){
    	// 조건1 : 모든 포인터가 범위내에 있다면
        if (l <= mid && r <= right){
        	// 두 포인터의 데이터를 비교해서 
            // 더 작은 데이터를 tmp에 넣고, 포인터를 하나 증가한다.
            if (arr[l] <= arr[r]){
            	tmp[idx++] = arr[l++];
            } else {
            	tmp[idx++] = arr[r++];
            }
        } 
        // 조건2 : left포인터만 범위내에 있다면
        else if (l <= mid && r > right){
        	tmp[idx++] = arr[l++];
        }
        // 조건3 : right포인터만 범위내에 있다면
        else {
        	tmp[idx++] = arr[r++];
        }
    }
    
    // tmp의 데이터를 arr에 옮긴다.
    for (int i = left; i <= right; i++){
    	arr[i] = tmp[i];
    }
}

 

2. 퀵소트

- 피봇이라는 기준값을 토대로 투포인터와 분할정복을 활용한 정렬 알고리즘이다.

- 1) 먼저 피봇값이라는 기준값을 지정하고 반정렬

- 2) 피봇값을 기준으로 배열을 분할

- 3) 분할된 배열을 부분적으로 정렬

void quickSort(int[] arr, int left, int right){
	// 탈출문
    if (left >= right) {
    	return;
    }
    
    // 피봇값을 지정
    int pivot = partition(arr, left, right);
    
    // 피봇값을 기준으로 배열을 분할
    quickSort(arr, left, pivot - 1);
    quickSort(arr, pivot + 1, right);
}

void int partition(int[] arr, int left, int right){
	// 투 포인터와 피봇값 지정
    int l = left;
    int r = right;
    int pivot = arr[left];
    
    // 피봇값을 기준으로 양 끝 포인터를 올리거나 내려준다
    while(l < r) {
    	while (arr[r] > pivot && l < r) {
        	r--;
        }
        
        while (arr[l] <= pivot && l < r) {
        	l++;
        }
        
        swap(arr, l, r);
    }
    // 기존 피봇값 위치 데이터와 피봇값을 교환
    swap(arr, left, l);
    
    return l;
}

 

3. 카라추바 알고리즘

- 카라추바라는 사람이 1960년에 만든 분할정복 알고리즘으로, 

- 초등학교 곱셈 공식에서 배웠던 각 자릿수를 곱하는 방식을 응용해 만든 알고리즘이다.

- 알고리즘 구현의 단계는 아래와 같다.

1. z0 = a * c
2. z1 = b * d
3. z2 = (a + b)(c + d)
4. z3 = z0 - ac - bd
5. (z0 * 10^n) + (z3 * 10^(n/2)) + z1

- 아래 코드 외에 아예 ArrayList를 사용해서 각 자릿수를 저장하는 방식 또한 있는데, 

  굉장히 복잡하기 때문에 관련된 코드는 검색을 통해 복사하여 사용하는 편이 좋을 것 같다.

** 자바에는 BigInteger라는 큰 수를 다루는 객체가 따로 있다.

  (큰 수의 곱셈은 이 객체의 multiply() 메소드를 쓰는 것이 코드를 가독성 있게 짜기에는 더 좋아 보인다.) 

public static long karatsuba(long x, long y) {
    // 범위가 작은 경우
    if (x <= 50 && y <= 50) {
        return x * y;
    }

    // a와 b의 자릿수
    int numXLen = (int)Math.log10(x);
    int numYLen = (int)Math.log10(y);

    // a와 b의 자릿수 중에 더 큰 자릿수를 선택
    int maxLen = Math.max(numXLen, numYLen); // ex 1234 -> 4

    // 분할한 자릿수
    Integer halfMaxLen = (maxLen / 2) + (maxLen % 2); // ex 1234 -> 2

    // Multiplier : 곱할 10^n
    long halfMaxLenTen = (long)Math.pow(10, halfMaxLen); // ex 1234 -> 10^2

    // 분할한 수들을 구한다.
    long a = x / halfMaxLenTen;
    long b = x % halfMaxLenTen;
    long c = y / halfMaxLenTen;
    long d = y % halfMaxLenTen;

    // 4단계에 따라 각 수들을 곱하고 더한다.
    // 1. a * c
    // 2. b * d
    // 3. (a+b)(c+d)
    // 4. (3)에서 (1), (2)를 뺀다
    // 5. (1) x halfMaxLen + (2) + (4) x (halfMaxLen / 2)
    long z0 = karatsuba(a, c);
    long z1 = karatsuba(b, d);
    long z2 = karatsuba(a + b, c + d);
    long z3 = z2 - z1 - z0;

    long res = (z0 * (long)Math.pow(10, halfMaxLen * 2)) + (z3 * (long)Math.pow(10, halfMaxLen)) + z1;
    return res;
}

 

|  백준 문제

- 백준의 분할 정복에 대한 문제는 사실상 재귀 문제와 별반 다를게 없었다.

- 그만큼 재귀와 분할정복이 서로 땔래야 땔 수 없는 관계라는 것을 의미하는 듯 하다.

https://www.acmicpc.net/workbook/view/798

 

문제집: 분할정복 (cokcjswo)

 

www.acmicpc.net

 

 

[ 출처 및 참조 ]

- 부트 캠프 강의를 들은 후 정리한 내용입니다.

- [Do it! 알고리즘 코딩 테스트 - 자바 편] 

- 나무위키,  https://namu.wiki/w/%EB%B6%84%ED%95%A0%20%EC%A0%95%EB%B3%B5%20%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98

https://www.geeksforgeeks.org/java-program-to-implement-the-karatsuba-multiplication-algorithm/

'Computer Science > Algorithm' 카테고리의 다른 글

[알고리즘] DP (동적 계획법)  (0) 2022.08.26
모듈러 산술  (0) 2022.08.25
[알고리즘] 그리디  (0) 2022.08.25
[알고리즘] 탐색 - DFS, BFS, 이진 탐색  (0) 2022.08.25
HashSet<int[]>와 Hashset<ArrayList<Integer>>  (0) 2022.08.17

|  그리디란?

- 그리디 알고리즘은, 매 선택에서 지금 이 순간 가장 최선이라 생각되는 답을 선택해 결과를 도출하는 것을 말한다.

- 여기서 Greedy을 직역하면 '탐욕'을 뜻한다.

 

- 왜 '탐욕'이라는 말을 쓸까?

  그건 지금 이 순간의 부분적인 최적해가 항상 종합적인 최적해는 아닐 수 있음에도,

  욕심쟁이와 같이 지금 보는 이 부분적인 선택이 전체의 최선이라 단정짓기 때문이다.

  rf. 여러 개의 도시가 연결된 도로가 있고, 그 도로 간에 이동 거리가 각각 다른 상황에서

      가장 이동거리가 짧은 거리를 찾아야한다고 할 때, 그리디를 쓰면 가장 짧은 도로들을 선택하는 게 될 수 있다.

- 정확함 보다는 적당히 맞는 답을 찾을 때 좋은 알고리즘이다. 따라서, 그리디 알고리즘을 근사 알고리즘으로도 부른다.

 

- 언제 쓰는 게 좋을까?

   탐욕 선택 속성, 최적 부분 구조 특정을 가진 문제를 해결하는 데에 강점이 있다.

탐욕 선택 속성 지금 선택이 다음 선택에 영향을 주지 않음
최적 부분 구조 전체 문제의 최적해는 부분 문제의 최적해로 이루어짐

   ex. 서울에서 대구를 거쳐 부산까지 가는 최단 경로 : 서울~대구 최단 경로 + 대구 ~ 부산 최단 경로

 

출처:나무위키

- 그럼 그리디로 풀지 못하는 문제들은 뭘로 풀어야 하지? 

  - 그리디로 풀지 못하는 문제들을 나무위키에서는 아래와 같이 두 가지를 소개했다.

  - 두 문제 모두 DP(동적 계획법)으로 풀 수 있는데, 두 가지 모두 차후 풀이 후 정리해보려고 한다.

외판원 문제 https://www.acmicpc.net/problem/2098
배낭 문제 https://www.acmicpc.net/problem/12865

 

- 그리디 알고리즘의 풀이 순서

  순서 예시 (ex. N구의 멀티탭 하나로 여러 제품을 사용할 때)
1 최적해 선택
: 지금 가장 최선이라 생각되는 해를 선택
ex. 이미 N개가 껴있는 상태에서 최소 교체 수 얻기
      - 지금 제품이 이미 껴 있으면 무시하고
      - 안 껴져 있으면 껴있는 것 중에
        내 다음으로 쓸 제품 중이 아닌 것과 교체        
2 적절성 검사
: 지금 고른 최적해가 전체 문제의 제약 조건을 벗어나는지 확인
ex. N개만 들어가야 하는 조건 성립하는가
3 해 검사
: 현재까지 선택한 해 집합이 전체 문제를 해결하는지 검사
ex. 지금까지 고른 최소값이 전체의 최소가 맞는가

 

|  대표적인 그리디 문제 

Activity Selection Problem 가장 많은 활동을 하려면? https://www.acmicpc.net/problem/12018
거스름돈 문제 가장 적은 동전의 수는? https://www.acmicpc.net/problem/11047

 

|  그리디 문제집

https://www.acmicpc.net/step/33

 

그리디 알고리즘 단계

동전의 조건이 특별해서 동적 프로그래밍보다 빠르게 답을 찾을 수 있는 문제

www.acmicpc.net

 

 

[ 참고 및 출처 ]

부트캠프 강의 후 정리

[Do it 알고리즘 코딩 테스트 - 자바 편]

나무위키

'Computer Science > Algorithm' 카테고리의 다른 글

모듈러 산술  (0) 2022.08.25
[알고리즘] 분할정복  (0) 2022.08.25
[알고리즘] 탐색 - DFS, BFS, 이진 탐색  (0) 2022.08.25
HashSet<int[]>와 Hashset<ArrayList<Integer>>  (0) 2022.08.17
[알고리즘] 정렬  (0) 2022.08.11

|  탐색이란?

주어진 데이터들 중에서 원하는 데이터를 찾아내는 알고리즘

 

|  탐색의 종류

  언제? 특징 시간복잡도
DFS(깊이 우선 탐색) 그래프의 모든 노드를
탐색하고자 할 때
- 재귀 또는 스택을 통해 구현
- 트리의 pre-order, in-order, post-order 순회 모두 DFS이다.
* 인접 행렬 : O(V+E)
* 인접 리스트 : O(V^2)
BFS(너비 우선 탐색) 그래프의 가까운 지점부터 탐색하고자 할 때 - 큐를 통해서 구현
- 트리의 level-order 가 BFS이다.
* 인접 행렬 : O(V+E)
* 인접 리스트 : O(V^2)
이진 탐색      

* DFS, BFS 모두 간선의 갯수가 적을 때에, 인접 리스트를 쓰는게 유리하다.

 

1. DFS (깊이 우선 탐색)

DFS란, 루트에서 시작하여 다음 분기로 넘어가기 전에 해당 분기를 완벽하게 탐색하는 방법이다.

[출처] https://gmlwjd9405.github.io/2018/08/14/algorithm-dfs.html

- 참조한 블로그에서는 미로를 탐색하는 것을 이야기했는데, 미로의 여러 갈랫길 중 첫번째 길만 쫒아가다가 다시 돌아와(backtracking) 방문하지 않은 곳을 탐색하여, 결국 모든 곳을 가는 것을 DFS라고 했다.

- 하나의 노드 A와 인접한 노드가 B, C가 있다고 할 때 먼저 B의 분기(인접한 노드들)를 모두 마쳐야만, C를 갈 수 있다.

- 트리의 level-order을 제외한 나머지 순회들과의 차이점은 어떤 노드를 방문했는지를 방문 배열을 통해 검사한다는 것.

 

출처:위키백과

(1) 구현 

스택 재귀 (순환 호출)
1. 시작 노드 정한 후, 사용할 자료구조 초기화
- 인접 리스트로 그래프 표현
- 방문 배열 초기화 후 시작지점 true 표시
- 시작 노드를 스택에 삽입

2. 스택에서 노드 꺼낸 후 인접 노드 다시 삽입하며 방문 체크

3. 스택에 값이 없을 때까지 2를 반복
1. 사용할 자료구조 초기화
- 인접리스트로 그래프 표현
- 방문 배열 초기화

2. 루트 노드(=시작 노드)를 방문하여 방문 체크

3. 인접한 노드들 중 방문하지 않은 곳을 방문

4. 방문할 노드들이 없을 때까지 3를 반복

- 백준의 아래 문제를 통해 한 번 구현해보았다.

[1] 먼저 자료구조를 초기화한다. : 정점/간선 갯수나, 인접리스트, 방문배열은 전역으로 빼주었다.

public class Ex11724 {

    static int N;
    static int M;
    static List<List<Integer>> graph;
    static boolean[] visited;
    static int cnt;

    public static void main(String[] args) throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());

        // 인접 리스트 그래프 초기화
        graph = new ArrayList<>();
        for (int i = 0; i <= N; i++) {
            graph.add(new ArrayList<>());
        }

        for (int i = 0; i < M; i++) {
            st = new StringTokenizer(br.readLine());

            int start = Integer.parseInt(st.nextToken());
            int end = Integer.parseInt(st.nextToken());

            graph.get(start).add(end);
            graph.get(end).add(start);
        }

        // 방문 배열 초기화
        visited = new boolean[N + 1];

        cnt = 0;
    }
}

[2] 문제에서 요구하는 연결망의 갯수 구하는 코드를 넣는다.

- 이 문제는 프로그래머스의 '네트워크' 문제와도 유사했는데, 분리된 연결망을 구하는 문제였다.

> 분기를 확인하기 위한 코드

// 2. dfs
for (int i = 1; i <= N; i++) {
    if (!visited[i]) {
        dfs_stack(i);
        cnt++;
    }
}

System.out.println(cnt);

> 예외 상황 : 노드가 하나밖에 없고 간선이 없는 경우 - 네트웍은 하나다.

// 노드가 하나밖에 없고 간선이 없어도 네트웍은 하나로 치부
if (N == 1 && M == 0) {
    System.out.println(1);
    return;
}

[3] 본격적인 dfs를 짜기

 

[3-1] 재귀 방식의 dfs

public static void dfs(int root) {

    // 루트 방문 체크
    visited[root] = true;

    // 인접한 노드들 중 방문하지 않은 곳을 방문
    for (int i = 0; i < graph.get(root).size(); i++) {

        int adjNode = graph.get(root).get(i);

        if (!visited[adjNode]) {
            dfs(adjNode);
        }
    }

}

 

[3-2] 스택 방식의 dfs

public static void dfs_stack(int start) {

    Stack<Integer> stack = new Stack<>();
    visited[start] = true;
    stack.push(start);

    while (!stack.isEmpty()) {
        int curNode = stack.pop();

        for (int i = 0; i < graph.get(curNode).size(); i++) {
            int adjNode = graph.get(curNode).get(i);

            if (!visited[adjNode]) {
                stack.push(adjNode);
                visited[adjNode] = true;
            }
        }
    }
}

[ 전체 코드 - 더보기 ]

더보기
package graph;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.StringTokenizer;


public class Ex11724 {

    static int N;
    static int M;
    static List<List<Integer>> graph;
    static boolean[] visited;

    static int cnt;

    public static void main(String[] args) throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());

        if (N == 1 && M == 0) {
            System.out.println(1);
            return;
        }

        // 1. 시작 노드를 정한 후 사용할 자료구조 초기화
        // 인접 리스트 그래프 초기화
        graph = new ArrayList<>();
        for (int i = 0; i <= N; i++) {
            graph.add(new ArrayList<>());
        }

        for (int i = 0; i < M; i++) {
            st = new StringTokenizer(br.readLine());

            int start = Integer.parseInt(st.nextToken());
            int end = Integer.parseInt(st.nextToken());

            graph.get(start).add(end);
            graph.get(end).add(start);
        }

        // 방문 배열 초기화
        visited = new boolean[N + 1];

        cnt = 0;

        // 2. dfs
        for (int i = 1; i <= N; i++) {
            if (!visited[i]) {
                dfs_stack(i);
                cnt++;
            }
        }

        System.out.println(cnt);
    }

    public static void dfs(int root) {

        // 루트 방문 체크
        visited[root] = true;

        // 인접한 노드들 중 방문하지 않은 곳을 방문
        for (int i = 0; i < graph.get(root).size(); i++) {

            int adjNode = graph.get(root).get(i);

            if (!visited[adjNode]) {
                dfs(adjNode);
            }
        }

    }

    public static void dfs_stack(int start) {

        Stack<Integer> stack = new Stack<>();
        visited[start] = true;
        stack.push(start);

        while (!stack.isEmpty()) {
            int curNode = stack.pop();

            for (int i = 0; i < graph.get(curNode).size(); i++) {
                int adjNode = graph.get(curNode).get(i);

                if (!visited[adjNode]) {
                    stack.push(adjNode);
                    visited[adjNode] = true;
                }
            }
        }
    }

}

 

(2) 시간 복잡도

- DFS는 그래프의 정점의 수(V)와 간선의 수(E)를 통해 시간 복잡도를 표현하는데,

- 인접 행렬을 사용하는 경우, 행으로는 전체 정점(V)을, 열로는 인접한 정점과의 연결 여부(E)를 확인하므로, 

  -- O(V^2) 의 시간 복잡도를 가진다.

- 인접 리스트를 사용하는 경우, 각 정점(V)을 방문한 후, 인접 노드를 따라 하나씩 탐색하기 때문에,

  -- O(V + E)의 시간 복잡도를 가진다.

- 그래프를 완전 탐색할 때에는 따라서, 간선이 적을 때에 인접 리스트를 사용하는 것이 좋다.

 

 

2. BFS (너비 우선 탐색)

bfs란, 루트에서 시작해서 인접한 노드를 먼저 탐색하는 방법

[출처] https://gmlwjd9405.github.io/2018/08/15/algorithm-bfs.html

- DFS의 경우, 깊이 있게 탐색했다면, BFS는 가까운 지점을 먼저 탐색하는 "넓은" 탐색이다.

- 참고한 블로그에서는, 두 노드 사이의 최단 경로 혹은 임의의 경로를 찾고 싶을 때에 이 방법을 쓴다고 했다.

- BFS를 활용한 알고리즘이 바로 최단 경로를 구하는 다익스트라였다. 

  * BFS와 차이점이 있다면, 다익스트라는 DP를 사용한다는 점..

https://why-dev.tistory.com/247?category=958869 

 

[알고리즘] 최단 경로 구하기 - 1. 다익스트라

| 다익스트라 - 가중치가 있는 그래프에서, 최단 경로를 구하는 알고리즘 - 핵심 : 그래프의 인접리스트와 DP를 이용 - 기능 : 출발 노드와 모든 노드 간의 최단 거리 탐색 - 특징 : 간선은 모두 양

why-dev.tistory.com

- BFS는 구현 방법을 정리하기 보다, 문제를 보면서 얘기해보려고 한다.

- 아래는, 프로그래머스의 게임 맵 최단 거리를 구하는 문제이다.

https://school.programmers.co.kr/learn/courses/30/lessons/1844#

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

(1) 코드

: 아래를 보면 알 수 있듯이, 게임 최단 거리를 구하는 문제는 BFS로 풀어야 했는데,

: 그 이유는 사방위로 움직여서 갈 수 있는 경로 중 도착지에 가까운 경로를 선택하려면,

  깊이있는 탐색보다는 너비 탐색을 통해서 사방위중 도착지에 가까운 방향 (아래로, 우측으로)으로 먼저 탐색을 하고,

  탐색한 횟수에 대해 저장하며 나아가야 했기 때문이다.

: DFS로 풀게될 경우에는 이런 탐색 횟수를 저장하며 갈 때 너무 많은 시간이 소요된다. 

  (왜냐면 깊이 탐색 후, 다시 제자리로 돌아와서 또 다른 갈래로 깊이 탐색 후, 또 다른 갈래로 깊이 탐색을 해야해서...)

: 그렇기에 그래프 최단 경로를 구할 때에도 BFS를 응용한 다익스트라를 사용한다.

import java.util.LinkedList;
import java.util.Queue;

public class Solution {

    class Node {
        int r;
        int c;
        int cnt;

        public Node(int x, int y, int cnt) {
            this.r = x;
            this.c = y;
            this.cnt = cnt;
        }
    }

    int[][] maps;
    int[][] dir = {{0, 1},{1, 0},{0, -1},{-1, 0}};

    public int solution(int[][] maps) {
        this.maps = maps;

        return bfs(maps.length, maps[0].length);
    }

    public int bfs(int r, int c){

        Queue<Node> q = new LinkedList<>();
        q.add(new Node(0, 0, 1));
        maps[0][0] = 0;

        while (!q.isEmpty()) {
            Node cur = q.poll();

            if (cur.r == r - 1 && cur.c == c - 1) {
                return cur.cnt;
            }

            for (int[] d : dir) {
                int newR = cur.r + d[0];
                int newC = cur.c + d[1];

                if (newR >= 0 && newC >= 0 && newR < r && newC < c) {
                    if (maps[newR][newC] == 1) {
                        maps[newR][newC] = 0;
                        q.add(new Node(newR, newC, cur.cnt + 1));
                    }
                }
            }
        }

        return -1;
    }
}

 

 

[ 참고 및 출처 ]

부트캠프 수업 내용 정리

[Do it 알고리즘 코딩 테스트 - 자바 편]

https://gmlwjd9405.github.io/2018/08/14/algorithm-dfs.html

https://gmlwjd9405.github.io/2018/08/15/algorithm-bfs.html

프로그래머스 

'Computer Science > Algorithm' 카테고리의 다른 글

[알고리즘] 분할정복  (0) 2022.08.25
[알고리즘] 그리디  (0) 2022.08.25
HashSet<int[]>와 Hashset<ArrayList<Integer>>  (0) 2022.08.17
[알고리즘] 정렬  (0) 2022.08.11
[알고리즘] 알고리즘 개요  (0) 2022.08.09

|  VIEW

- 가상의 읽기 전용 테이블

- 장점 :

  - 독립성 : 테이블 구조가 변경되어도 뷰를 쓰는 응용 프로그램은 변경하지 않음

  - 편리성 : 복잡한 쿼리를 뷰로 생성하여 코드를 간결화

  - 보안성 : 계정 권한 수준에 따라 노출되지 않아야 하는 데이터를 숨김 처리 할 수 있음

-- 기본 구문
CREATE VIEW 뷰명 AS
SELECT *
FROM 테이블명

-- 예시
create view v_member as
select
    m.member_type, m.user_id,m.name,
    md.mobile_no, md.marketing_yn, md.register_date
from member as m
    join member_detail md
        on m.member_type = md.member_type and m.user_id = md.user_id
;

 

|  (사용자 정의)함수와 프로시져

  (사용자 정의)함수 프로시져
언제쓰나? 자주쓰는 기능 저장할때 특정 비즈니스 로직을 저장해서 꺼내 쓸 때
공통점 선언부와 구현부가 있는 함수 형태
차이점 반환값 O 반환값 X

A. 함수

-- 기본 구문
CREATE FUNCTION 함수명(매개변수명 타입)
   RETURNS 반환타입
BEGIN
   RETURN
   구현부
END;

-- 예시
-- A. 생성
create function sf_password(password varchar(255))
  returns varchar(255)
begin
  return
  	case 
  	   when length(password) > 2 then 
  	        concat(substring(password, 1, 2), '**')
  	   else '****'
    end;
end;

-- B. 호출
select 
   sf_password(password) as password_mask
from member;

-- C. 삭제
drop function sf_password;

B. 프로시저

-- 기본 구문
CREATE PROCEDURE 함수명()
BEGIN
	구현부
END
;

-- 예시
-- A. 생성
create procedure sp_select_memeber()
begin
    select *
    from member;

    select *
    from member_detail;
end;

-- B. 호출
call sp_select_memeber();

-- C. 삭제
drop procedure sp_select_memeber;

 

C. delimiter를 사용해야 할까?

- 원칙적으로, 함수나 프로시저를 생성할 때, delimiter를 사용하는 것이 필요하다.

  ** delimiter 곧, SQL 명령어 간의 구분은 기본적으로 세미콜론(';')을 통해 이루어지기에,

     SQL 명령어를 구현부에 중첩시키면 하위 명령어는 실행되지 않는 현상이 발생)

- 다만, 툴을 사용하면 delimiter를 사용하지 않아도 오류 없이 잘 실행된다.

delimiter $$  -- delimiter 변경
create procedure sp_select_memeber()
begin
    select *
    from member;

    select *
    from member_detail;
end;
delimiter ;  -- delimiter default인 ;로 원상복구

 

|  트리거

특정 조건이 만족되면 자동으로 실행 시작

rf. 일반적으로 히스토리를 남기는 데에 사용된다.

rf. 상황에 따라 양날의 검이 될 수 있는 명령문이다. (사용에 주의가 필요)

event old new
insert X O
update O O
delete O X
-- RQ. MEMBER 테이블의 핸드폰 번호를 갱신(update)할 때마다 히스토리를 남기고 싶다.

-- A. 변경 사항 담을 히스토리 테이블
create table member_detail_history
(
    id int auto_increment primary key ,
    member_type varchar(10),
    user_id varchar(50),
    mobile_no varchar(50),
    new_mobile_no varchar(50),
    update_date datetime
);

-- B. 트리거 예시
delimiter &&
create trigger tg_member_mobile_no_history
    before update on member_detail -- update 되기 이전에 트리거가 일어난다.
    for each row
    begin
        insert into member_detail_history
        (
          member_type,
          user_id,
          mobile_no,
          new_mobile_no,
          update_date
         )
        values
        (
          old.member_type,
          old.user_id,
          old.mobile_no,
          new.mobile_no,
          now()
        );
    end;
delimiter ;

 

 

[ 출처 ]

- 부트캠프 강의를 들은 후 정리한 내용입니다.

|  ALIAS와 * (애스터리스크)

- ALIAS : 별명, 별칭

- * : 전체

select
    m.id as 회원아이디,
    m.password as 비밀번호,
    m.name as 회원명
from member as m;

 

|  JOIN문

- JOIN만 적히는 경우 INNER JOIN이 사용된다.

INNER JOIN
키 값 기준 데이터 결합
LEFT JOIN
키 값 기준 데이터 결합 + 좌측의 나머지 
RIGHT JOIN
키 값 기준 데이터 결합 + 우측의 나머지
FULL JOIN
LEFT데이터 X  RIGHT데이터

- 수업에서 제공되었던 테이블은, MEMBER와 MEMBER_DETAIL 이었는데,

  이와 같이 회원 정보를 간편 정보 / 상세 정보로 나누어서 필요에 따라 테이블을 조인하는 식으로 사용한다고 한다.

-- 회원정보 > 로그인 정보
create table member
(
   member_type varchar(10) not null comment '회원구분',
   user_id     varchar(50) not null comment '회원 아이디',
   password    varchar(50) null     comment '비밀번호',
   name        varchar(20) null     comment '이름',
   primary key (member_type, user_id)
) comment '회원정보';

-- 회원상세정보 > 로그인에 필요하지 않은 이외 정보
create table member_detail
(
   member_type   varchar(10)                          not null comment '회원구분',
   user_id       varchar(50)                          not null comment '회원 아이디',
   mobile_no     varchar(12)                          null     comment '휴대폰 번호',
   marketing_yn  bit                                  null     comment '마케팅 수신 여부',
   register_date datetime default current_timestamp() null comment '가입일',
   primary key (member_type, user_id),
   constraint fk_member_detail foreign key (member_type, user_id) references member (member_type, user_id)
) comment '회원상세정보';

- JOIN 코드

-- 조인 (INNER JOIN)
-- ** 단순히 select * from.. 을 쓰면 어떤 DBMS에서는 오류가 날 수 있다.
select
    m.*,
    md.*
from member as m
    join member_detail as md
        on m.member_type = md.member_type and m.user_id = md.user_id
;

-- 중복된 컬럼 제외
select
    m.member_type, m.user_id, m.password, m.name,
    md.mobile_no, md.marketing_yn, md.register_date
from member as m
    join member_detail as md
        on m.member_type = md.member_type and m.user_id = md.user_id
;

-- LEFT JOIN : member(left)를 기준으로 member_detail(right)와 키값이 동일한 데이터를 먼저 솎아내고, 그 후에 member의 나머지를 추가
select
    m.member_type, m.user_id, m.password, m.name,
    md.mobile_no, md.marketing_yn, md.register_date
from member as m
    left join member_detail as md
        on m.member_type = md.member_type and m.user_id = md.user_id
;

-- RIGHT JOIN : RIGHT를 기준으로
select
    m.member_type, m.user_id, m.password, m.name,
    md.mobile_no, md.marketing_yn, md.register_date
from member as m
    right join member_detail as md
        on m.member_type = md.member_type and m.user_id = md.user_id
;

-- FULL JOIN : LEFT x RIGHT
select
    m.member_type, m.user_id, m.password, m.name,
    md.mobile_no, md.marketing_yn, md.register_date
from member as m
    join member_detail as md
;

 

|  내장함수

- 각 DBMS별로 내장되어 있는 함수들이 있다.

- 구분

입력값의 갯수에 따라 - 단일행 함수 : 함수의 입력값이 단일행 값일 때
- 다중행 함수 : 함수의 입력값이 다중행 값일 때 (ex. 집계 함수, 그룹 함수)
데이터 타입에 따라 - 문자형 함수
- 숫자형 함수
- 날짜형 함수
- 변환형 함수 : 데이터 타입 변환
- NULL 관련 함수

- SQL 조건문 : CASE ~ END 

-- SQL 조건문 : 자바의 switch case와 동일
CASE 
  WHEN 조건 THEN 실행
  ELSE 실행
END

- 수업에서 다루었던 코드

-- A. 문자형
-- (1) 비밀번호 * 처리 (substring, length, concat)
-- 오라클의 경우, 문자열 결합 시 : concat(문자열, 결합할 문자) 또는 문자열 || 결합할문자
SELECT
    member_type,
    user_id,
    password,
    name,
    -- concat(substring(password, 1, 2), '**') as password_mask, -- idx가 1부터 시작
    -- length(password) as password_length,
    case
      when length(password) > 2 then concat(substring(password, 1, 2), '**')
      else ''
    end as password_mask
FROM member;

-- B. 데이터 포맷 변환
SELECT register_date,
       date_format(register_date, '%Y.%m.%d') as dt_format
FROM member_detail;

SELECT
    '20220321',
    str_to_date('20220321', '%Y%m%d') as dt_date,
    date_add(str_to_date('20220321', '%Y%m%d'), interval 1 month) as dt_date2
FROM dual;

-- 현재 날짜를 통해 월초와 월말을 구하기
SELECT
    date_format(now(), '%Y-%m-%01') as start_date, -- 이번달 첫일
    date_add(date_add(str_to_date(date_format(now(), '%Y-%m-01'), '%Y-%m-%d'), interval 1 month), interval -1 day) as end_date
FROM dual;

- 보다 자세한 내장 함수 코드 

https://2030bigdata.tistory.com/219

 

[개미의 걸음 SQLD 2과목] SQL내장함수① 단일행(문자열, 숫자형, 날짜형, 형변환, NULL)함수

함수[Function] 내장함수[표준함수] SQL에서 기본적으로 내장하고 있어 표준으로 제공하는 함수 사용자 정의함수 SQL에서 사용자가 임의로 만들어서 사용하는 함수 내장 함수[BUILT-IN Function] SQL에서

2030bigdata.tistory.com

 

|  페이징 처리

- 다수의 게시글(또는 카드 등)을 특정 위치에서 특정 갯수만큼 보여주는 것

MySQL, MariaDB LIMIT를 통해 페이징 처리
Oracle ROWNUM을 통해 페이징 처리
MSSQL OFFSET, FETCH를 통해 페이징 처리

📡 MySQL/MariaDB

--!! 주의사항 !! 특히하게 LIMIT은 idx를 0부터 시작한다.

-- 전체 data에 대해 첫번째부터 10개만 출력
SELECT *
FROM member
LIMIT 0, 10; 

-- 나열된 data에 대해 10번째부터 10개만 출력
select
    c.code, c.company_name, c.eng_company_name, c.category,
    row_number() over (order by c.code desc) as row_index
from company c
order by c.code desc
limit 10, 10
;

-- 범위를 지정하여 출력
select *
from
(
    select *
    from
    (
        select
        c.code, c.company_name, c.eng_company_name, c.category,
        row_number() over (order by c.code desc) as row_index
        from company c
        order by c.code desc
    ) t1
    where row_index <= 30
) t2
where row_index > 20;

📡 ORACLE

-- 기본 구문
--- '*'을 사용하면 데이터가 깨진다.
--- 테이블.* 또는 칼럼명을 하나씩 작성 필요.
SELECT
  칼럼1,
  칼럼2,
  ROWNUM as rnum
FROM member
ORDER BY 순서기준

-- 실제 사용
SELECT *
FROM (
		SELECT 
          a.*, ROWNUM as rnum 
        FROM (
                SELECT 
                  * FROM member
                ORDER BY member_no
             ) a
     ) 
WHERE rnum >= 1 AND rnum <= 10;

 

 

[ 참조 및 출처 ]

부트캠프 강의를 들은 후 정리한 내용입니다.

https://programmer93.tistory.com/4

https://m.blog.naver.com/wideeyed/221796538283

+ Recent posts