문제 링크

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

 

14889번: 스타트와 링크

예제 2의 경우에 (1, 3, 6), (2, 4, 5)로 팀을 나누면 되고, 예제 3의 경우에는 (1, 2, 4, 5), (3, 6, 7, 8)로 팀을 나누면 된다.

www.acmicpc.net

이전에 풀었던 스타트와 링크 문제를 순열을 이용해 다시 풀어봤다.

각 팀별로 수가 정해져있기 때문에 순열을 활용해 풀 수 있다. 참고로 링크와 스타트 문제 같은 경우에는 팀원의 수가 정확하게 정해져있지 않으므로 순열을 통한 풀이가 불가능하다. 

 

전체 인원을 절반으로 나누어 앞의 절반은 0으로 뒤의 절반은 1로 마킹한 후 순열을 이용해 다음 순열을 넣어가며

전체를 탐색하도록 코드를 짰다.

매 정답이 구해질 때마다 기존의 값이랑 비교해서 더 값이 작다면 그 값이 정답으로 들어가도록 풀었다.

 

해결 코드 

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int n;

int solve(vector<vector<int> > &a, vector <int> &b){
    vector <int> zero,one;
    for(int i=0;i<n;++i){
        if(b[i])
            one.push_back(i);
        else
            zero.push_back(i);
    }
    int z=0; int o=0;
    for(int i=0;i<n/2;++i){
        for(int j=0;j<n/2;++j){
            if(i==j)
                continue;
            z+=a[zero[i]][zero[j]];
            o+=a[one[i]][one[j]];
        }
    }
    int diff=abs(z-o);
    return diff;
}

int main () {
    ios_base::sync_with_stdio(0); cin.tie(NULL);
    //input 받기
    cin>>n;
    vector<vector<int> > arr(n,vector<int>(n));
    for(int i=0;i<n;++i){
        for(int j=0; j<n; ++j){
            cin>>arr[i][j];
        }
    }
    //로직
    vector <int> b(n);
    for(int i=0;i<n/2;++i){
        b[i]=1;
    }
    sort(b.begin(),b.end());
    int ans=999999999;
    do{
        int diff=solve(arr,b);
        if(ans>diff) ans=diff;
    }while(next_permutation(b.begin(),b.end()));
    //output
    cout<<ans<<'\n';
    return 0;
}

@Scheduled  어노테이션

주기적으로 해야되는 작업을 쉽게 적용할 수 있도록 도와주는 어노테이션

스프링 3.1 이상부터 지원 

 

@Scheduled  사용 준비

@SpringBootApplication 어노테이션이 있는 어플리케이션 자바 파일에 @EnableScheduling 어노테이션 추가

@SpringBootApplication
@EnableScheduling
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

@Scheduled  사용 

1. cron 

cron 표현식을 지원

초 분 시 일 월 주(년) 순으로 표기 

@Scheduled(cron = "0 0 9 * * *") //매일 9시마다
public void TestScheduler(){
        System.out.println("테스트");
}
0 ~ 59
0 ~ 59
0 ~ 23
1 ~ 31
1 ~ 12 
요일 1 ~ 7 (1 => 일요일, 7=> 토요일) 
년도 1970 ~ 2099

* : 모든 값

? : 특정 값 없음

- : 범위 지정에 사용

, : 여러 값 지정 구분에 사용

/ : 초기값과 증가치 설정에 사용

L : 지정할 수 있는 범위의 마지막 값

W : 월~금요일 또는 가장 가까운 월/금요일

# : 몇 번째 무슨 요일 2#1 => 첫 번째 월요일

 

사용 예시

 "0 0 02 * * ?" : 매일 새벽 두시

 "0 0 12 * * ?" : 매일 정오

 "0 15 10 ? * *" : 모든 요일, 매월, 아무 날이나 10:15:00 

 "0 15 10 * * ? *" : 모든 연도, 아무 요일, 매월, 매일 10:15 

 "0 0/5 14,18 * * ?" : 아무 요일, 매월, 매일, 14시, 18시 매 5분마다 0초 

 "0 0-5 14 * * ?" : 아무 요일, 매월, 매일, 14:00 부터 매 14:05까지 매 분 0초 

 "0 10,30 14 ? 6 WED" : 6월의 매 수요일, 아무 날짜나 14:10:00, 14:30:00 

 "0 15 10 L * ?" : 아무 요일, 매월 마지막 날 10:15:00 

 "0 15 10 ? * 7L" : 매월 마지막 토요일 아무 날이나 10:15:00 

 "0 15 08 ? * 6L 2002-2005" : 2002년부터 2005년까지 매월 마지막 금요일 아무 날이나 0815:00 

 "0 15 08 ? * 6#3" : 매월 3번째 금요일 아무 날이나 08:15:00

 

2. fixedDelay 

해당 메소드가 종료된 시점부터 다음 메소드 실행 시점까지의 주기

시간 단위는 밀리세컨드

@Scheduled(fixedDelay=1000)
public void TestScheduler(){
        System.out.println("테스트");
}

3. fixedRate

해당 메소드가 시작된 시점부터 다음 메소드 실행 시점까지의 주기

시간 단위는 밀리세컨드

@Scheduled(fixedRate=1000)
public void TestScheduler(){
        System.out.println("테스트");
}

 

 

참고 사이트

https://rooted.tistory.com/12

https://toma0912.tistory.com/17

https://jeong-pro.tistory.com/186

https://java119.tistory.com/34
https://javafactory.tistory.com/1386

현재 일하는 곳에서 개발 중인 앱에 firebase를 통해 푸시 알림을 보내고 sms를 전송하는 부분이 있다. 관련된 부분을 수정을 해야하는 상황이라 fcm이 뭐고 어떤 방식으로 돌아가는지 알아볼 겸 글을 작성하게 됐다. 

FCM이란?

구글에서 무료로 메시지를 안정적으로 전송할 수 있는 교차 플랫폼 메시징 솔루션

앱 서버에서 FCM 서버로 메시지 요청이 가고 이를 받은 FCM 서버가 클라이언트에게 메시지를 보낸다.

쉽게 말해 서비스 회사의 서버와 클라이언트 사이에 FCM 서버가 존재하는 거다.

 

그래 메시지 보내주는 거 알겠어,,근데 왜 이렇게 메시지를 보내는데? 뭐가 다른걸까

 

사용자 김씨에게 어떠한 메세지를 전달해야한다고 가정해보자.

김씨에게 메세지를 어떻게 전달할 수 있을까

서비스 회사의 서버에서 김씨에게 메세지를 보내면 된다.

문제는 김씨가 실시간으로 서버로 부터 메세지를 받으려면 서버에 계속 접속해 있어야 한다.

이러한 방식을 사용하면 배터리도 빨리 딣고 네트워크 사용에도 문제가 발생한다.

이때 FCM을 사용하면 문제를 해결할 수 있다.

중간에 FCM 서버가 끼므로 서비스 회사의 서버에 항상 접속해 있지 않아도 되기 때문이다.

서비스 프로그램이 실행 중이 아니더라도 리스너를 통해 메시지를 수신받을 수 있다.

 

FCM을 통한 메시지 전송 흐름(FE+BE)

1. 클라이언트에서 FCM 서버로부터 FCM 토큰을 요청하고 획득한다.

2. 클라이언트에서 서버한테 해당 토큰을 전달하고 서버는 전달 받은 토큰을 디비에 저장한다.

3. 서버가 전달 받은 토큰을 이용해 FCM 서버로 메시지 전송 요청을 보낸다.

4. 요청을 받은 FCM 서버가 사용자에게 메시지를 전송한다.

5. 사용자가 사용 중인 서비스에서 리스너를 통해 메시지를 받는다.

 

FCM 토큰 만료 케이스

FCM 토큰은 만료되지 않으나, 다음과 같은 특정 케이스들에선 변경된다.

1. 앱 instance ID 삭제

2. 앱 삭제 혹은 재설치

3. 앱 사용자가 앱 데이터 삭제


FCM 라이브러리 추가(BE, build.gradle)

dependencies {
    ...
    
    implementation 'com.google.firebase:firebase-messaging:21.1.0'
}

 

FCM 메시지 종류 2가지

1. notification message

title과 body로 구성

fcm SDK에서 자동으로 처리

{
  "message":{
    "token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
    "notification":{
      "title":"Portugal vs. Denmark",
      "body":"great match!"
    }
  }
}

2. data message

key-value 쌍으로 구성

클라이언트 앱에서 처리

{
  "message":{
    "token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
    "data":{
      "Nick" : "Mario",
      "body" : "great match!",
      "Room" : "PortugalVSDenmark"
    }
  }
}

 

FCM 서버 메시지 요청 방법 4가지

1. Firebase Admin SDK 이용(원시 프로토콜)

Node.js자바PythonC#Go 지원

2. HTTP V1 API 이용

가장 최신 프로토콜, firebase admin sdk는 이 프로토콜을 기반으로

대부분의 사례에 이 API 사용 추천

3. 기존 HTTP API 이용

4. XMPP 서버

전송하는 각 메시지를 고유하게 구별하기 위해 서버에서 메시지 ID를 생성할 수 있어야 함

 

 

 

 

 

 

참고 사이트

https://firebase.google.com/docs/cloud-messaging/

https://developer88.tistory.com/159

https://team-platform.tistory.com/23

https://medium.com/@vdongbin/firebase%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-push-notification-5c8a83932472

https://maejing.tistory.com/entry/Android-FCM%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%B4-Push-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0

 

사용 준비

헤더파일 추가

#include <algorithm>

 

사용

함수에 배열의 주소 또는 벡터의 iterator를 넣어주면 다음 순열과 이전 순열을 구할 수 있다. 

 

next_permutation 함수 

현재 수열에서 인자로 넘어간 범위에 해당하는 다음 순열을 구해주는 함수

다음 순열이 존재해 구할 수 있다면 true 반환 다음 순열이 없다면 false 반환

// 첫번째 인자:순열의 시작, 두번째 인자:순열의 끝
bool next_permutation (BidirectionalIterator first, BidirectionalIterator last);

예시 코드

vector <int> min(k);
do{
      for(int i=0; i<4; i++){
			cout << v[i] << " ";
		}

		cout << '\n'; 
}while(next_permutation(min.begin(),min.end()));

prev_permutation 함수

현재 수열에서 인자로 넘어간 범위에 해당하는 이전 순열을 구해주는 함수

이전 순열이 존재해 구할 수 있다면 true 반환 이전 순열이 없다면 false 반환

//직접 비교함수를 넣어주는 경우
bool next_permutation (BidirectionalIterator first, BidirectionalIterator last, Compare comp);

예시 코드

vector <int> min(k);
do{
      for(int i=0; i<4; i++){
			cout << v[i] << " ";
		}

		cout << '\n'; 
}while(prev_permutation(min.begin(),min.end()));

 

참고 사이트

https://twpower.github.io/82-next_permutation-and-prev_permutation

'프로그래밍 언어 > c++' 카테고리의 다른 글

C++ sort 함수 compare 커스터마이징  (0) 2022.06.03
[STL] 덱(Deque)  (0) 2021.10.12
[STL] 큐(Queue)  (0) 2021.10.11
[STL] vector 컨테이너  (0) 2021.09.19
STL  (0) 2021.09.19

직렬화

자바 객체를 전송 가능한 상태로

 

직렬화 어노테이션들

@JsonAnyGetter

map 필드를 다룰 때 편리

map 필드가 한 번 감싸져서 나옴

public class Member {
    public String name;
    private Map<String, String> properties;

    @JsonAnyGetter
    public Map<String, String> getProperties() {
        return properties;
    }
}

@JsonGetter

@JsonProperty 어노테이션의 대안

메소드의 이름을 getter 메소드로 표현

public class Member {
    public int studentCode;
    private String name;

    @JsonGetter("name")
    public String getTheName() {
        return name;
    }
}

@JsonPropertyOrder

직렬화 하는 속성의 순서를 정함

@JsonPropertyOrder({ "name", "studentCode" })
public class Member {
    public int studentCode;
    public String name;
}

@JsonRawValue

Jackson이 속성을 그대로 직렬화

public class Member {
    public String name;

    @JsonRawValue
    public String deep;
}

output 예시

//적용 후
{
    "name":"My bean",
    "deep":{
        "attr":false
    }
}
//적용 전
{
  "name": "yun",
  "deep": "{\n  \"attr\":false\n}"
}

@JsonValue

@JsonValue 해당 멤버 필드 이름을 통해 직렬화

public enum Member {
    TYPE1(1, "Type A"), TYPE2(2, "Type 2");
    
    private Integer studentCode;
    private String name;

    @JsonValue
    public String getName() {
        return name;
    }
}

@JsonRootName

root wrapper의 이름을 설정할 수 있음

@JsonRootName(value = "user")
public class Member {
    public int studentCode;
    public String name;
}

아웃풋 예시

{
    "user":{
        "studentCode":1,
        "name":"John"
    }
}

 

 

참고 사이트 

https://www.baeldung.com/jackson-annotations

https://pjh3749.tistory.com/281

https://cheese10yun.github.io/jackson-annotation/

 

게시글 목록을 조회할 때 페이지 번호로 목록이 구분되는 걸 많이 본적이 있을 거다.

한 화면에 모든 글을 보여줄 수 없기 때문에 페이지로 나눠 게시글 목록을 보여주는 것인데 오늘은 이 페이징 처리에 관해 글을 써보려고 한다.

 

이 기능을 실제로 하나하나 구현할 시 상당히 번거로운데 Spring Data JPA에서는 Pageable을 이용해 손쉽게 페이징 처리를 할 수 있도록 도와준다. 이떄 단순하게 pagination만 해주는 게 아니라 보여지는 목록에 정렬이 필요한 경우 sorting도 같이 할 수 있다.

 

1. 페이징 처리할 레포지토리에 JPARepositoy를 상속한다.

@Repository
public interface postRepository extends JpaRepository<Post, Long> {
	List<Post> findAll(Pageable pageable);
}

2. 페이징 처리

pageable 객체를 만들어 repository의 메소드에 인자로 전달하면 된다.

Pageable pageable = PageRequest.of(현재 페이지 넘버, 조회할 페이지의 수, 정렬관련정보들);

2-1. 페이징 처리

Pageable pageable = PageRequest.of(page - 1, 10);
repo.메소드명(pageable);

페이지 번호는 0번 부터 시작해 1을 빼줘야한다.

 

2-2. 페이징 처리+정렬

Pageable pageable = PageRequest.of(0, 3, Sort.by("postId").descending());
repo.메소드명(pageable);

 

 

참고자료

 

https://www.baeldung.com/spring-data-jpa-pagination-sorting

https://velog.io/@jjun_meatlov/Spring-Data-JPA-%ED%8E%98%EC%9D%B4%EC%A7%95-%EC%B2%98%EB%A6%AC%ED%95%98%EA%B8%B0

https://devlog-wjdrbs96.tistory.com/414

http://devstory.ibksplatform.com/2020/03/spring-boot-jpa-pageable.html

 

토비의 스프링 3.1 책을 읽으며 일부분을 정리한 내용입니다. 
개념 이해를 위한 내용들 중 일부분을 정리했으므로 이해를 돕기위한 예시 코드들 및 자세한 전체적인 내용은 책을 통해 확인하시길 바랍니다.
포스팅 내용이 저작권의 문제가 발생할 경우 게시물은 바로 삭제/비공개 처리됩니다.

트랜잭션 속성

public Object invoke(MethodInvocation invocation) throws Throwable {
    TransactionStatus status = this.transactionManager.getTransaction(new DefaultTransactionDefinition());
    
    try {
        Object ret = invocation.proceed();
        this.transactionManager.commit(status);
        return ret;
    } catch(RuntimeException e) {
        this.transactionManager.rollback(status);
        throw e;
    }
}

 

DefaultTransactionDefinition이 구현하고 있는 TransactionDefinition 인터페이스는

트랜잭션의 동작방식에 영향을 줄 수 있는 4가지 속성 정의

1. 트랜잭션 전파

트랜잭션의 경계에서 이미 진행 중인 트랜잭션이 있을 때 또는 없을 때 어떻게 동작할 것 인가를 결정하는 방식

 

PROPAGATION_REQUIRED

진행 중인 트랜잭션이 없으면 새로 시작하고, 이미 시작된 트랜잭션이 있으면 이에 참여한다.

RPOPAGATION_REQUIRES_NEW

항상 새로운 트랜잭션을 시작

PROPAGATION_NOT_SUPPORTED

진행 중인 트랜잭션이 있어도 무시

->여러 메소드 동작시 특정 메소드만 트랜잭션 적용을 제외시키기 위해 사용

 

2. 격리 수준

서버환경에서는 여러 개의 트랜잭션이 동시에 진행될 수 있으므로 DB 트랜잭션은 격리수준을 갖고 있어야 한다. 

적절한 격리수준을 조정해서 가능한 여러 트랜잭션을 동시에 진행하면서 문제가 발생하지 않는 제어가 필요
기본적으로 DB에 설정되어 있지만 DataSource 등에서 재설정 가능

DefaultTransactionDefinition에 설정된 격리수준은 ISOLATION_DEFAULT
->DataSource에 설정되어 있는 디폴트 격리수준을 그대로 따른다는 뜻

3. 제한 시간

트랜잭션을 수행하는 제한 시간

DefaultTransactionDefinition의 기본 설정은 제한시간 x

제한시간은 트랜잭션을 직접 시작할 수 있는 PROPAGATION_REQUIRED나 RPOPAGATION_REQUIRES_NEW와 함께 사용해야만 유의미

4. 읽기 전용

트랜잭션 내에서 데이터 조작하는 시도 방지

 

 

TransactionInterceptor

스프링에서 제공하는 트랜잭션 경계설정 어드바이스

프로퍼티

PlatformTransactionManager

Properties 타입의 transactionAttributes

네 가지 기본 항목을 정의한 TransactionDefinition 인터페이스

+ rollbackOn() 메서드를 가지고 있는TransactionAttribute 인터페이스

rollbackOn() 메서드는 롤백을 수행할 예외상황을 결정하는 메서드

메서드 패턴을 키로, 트랜잭션 속성을 값으로 

 

메서드 패턴

  • ROPAGATION_NAME : 필수항목, PROPAGATION_ 으로 시작
  • ISOLATION_NAME : 생략가능, ISOLATION_으로 시작
  • readOnly : 생략가능, 읽기전용
  • timeout_NNNN : 생략가능, 제한시간 지정. NNNN은 초단위로 지정
  • -Exception1 : 한 개 이상 등록가능, 체크 예외중 롤백 대상으로 추가할 것
  • +Exception2 : 한 개 이상 등록가능, 런타임이지만 롤백되지 않을 예외 지정

트랜잭션 속성 정의 예시

    <bean id="transactionAdvice" 
              class="org.springframework.transaction.interceptor.TransactionInterceptor">
        <property name="transactionManager" ref="transactionManager"/>
        <property name="transactionAttributes">
            <props>
                <prop key="get*">PROPAGATION_REQUIRED,readOnly,timeout_30</prop>
                <prop key="upgrade*">PROPAGATION_REQUIRES_NEW,ISOLATION_SERIALIZABLE</prop>
                <prop key="*">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
    </bean>

TransactionInterceptor는 2가지 예외 처리 방식 제공

1. 런타임 예외의 경우 트랜잭션은 롤백

2. 체크 예외를 던지는 경우 비즈니스 로직에 따라 개발자가 의도한 예외라 해석하고 트랜잭션을 커밋

 

위 2가지 상황에 부합하지 않는 예외는 rollbackOn() 메서드 활용

 

tx 네임스페이스

TransactionInterceptor 타입의 어드바이스 빈과 TransactionAttribute 타입의 속성 정보도 tx 스키마의 전용 태그를 이용해 정의 가능

 

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                            https://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/aop
                            http://www.springframework.org/schema/aop/spring-aop.xsd
                            http://www.springframework.org/schema/tx
                            http://www.springframework.org/schema/tx/spring-tx.xsd">

         ...
    <tx:advice id="transactionAdvice", transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="get*" /*속성들*/ />
                        <tx:method name="upgrade*" propagation="..." isolation="SERIALIZABLE"/>
            <tx:method name="*" />
        </tx:attributes>
    </tx:advice>

 

포인트 컷과 트랜잭션 속성의 적용 전략

  1. 트랜잭션 포인트컷 표현식은 타입 패턴이나 빈 이름을 이용
    • 트랜잭션을 적용할 타깃 클래스의 메서드는 모두 트랜잭션 적용 후보
    • 읽기 전용 메서드도 트랜잭션 적용
    • execution() 방식의 포인트컷 대신 bean() 표현식을 사용하는 것도 고려
  2. 공통된 메서드 이름 규칙을 통해 최소한의 트랜잭션 어드바이스와 속성을 정의
    • get, find와 같이 조회전용 메서드의 접두어를 정해두기
  3. 프록시 방식 AOP는 같은 타깃 오브젝트 내의 메서드를 호출할 때는 적용되지 않는다.

 

트랜잭션 속성 적용

1. 트랜잭션 경계설정의 일원화

트랜잭션 경계설정 부가기능을 다양한 계층에서 중구난방으로 적용하는 것은 좋지 않다.

일반적으로 서비스 계층 오브젝트 메서드가 가장 적절

서비스 계층을 트랜잭션 경계로 정했다면, DAO에 직접 접근은 지양

 

2. 서비스 빈에 적용되는 포인트컷 표현식 등록

포인트컷 표현식을 비즈니스 로직의 서비스 빈에 적용되도록 작성

 

3.트랜잭션 속성을 가진 트랜잭션 어드바이스 등록

TransactionInterceptor를 tx:advice 태그를 이용해 등록하고, attributes를 잘 정의

데이터 타입 설명
auto_increment 행 추가 시 자동으로 1씩 증가
not null null 값 못들어감
unique 같은 열 값 중복 불가능
primary key not null&unique
default 입력 되는 값 없으면
지정된 값이 들어감

 

테이블 생성

CREATE TABLE 테이블명 (
 컬럼명1 데이터타입,
 컬럼명2 데이터타입
);

테이블 삭제

DROP TABLE 테이블이름;

테이블 수정

ALTER TABLE 수정할테이블명
RENAME TO 수정될테이블명

ADD COLUMN 추가할컬럼명 데이터타입 // 컬럼 추가

CHANGE COLUMN 기존컬럼명 바꿀컬럼명 데이터타입, // 기존 컬럼명 변경

CHANGE COLUMN 컬럼명 컬럼명 바꿀데이터타입, //기존 컬럼 데이터타입 변경

DROP COLUMN 컬럼명; //컬럼 삭제

특정 컬럼 데이터 추가

INSERT INTO 테이블명

(컬럼명1, 컬럼명2)

VALUES(값1, 값2);

전체 컬럼 데이터 추가

INSERT INTO 테이블명

VALUES(값1, 값2, 값3)

데이터 삭제

DELETE FROM 테이블명

WHERE 조건;

데이터 수정

UPDATES 테이블명

SET 컬럼명1 = 값1, 컬럼명2 = 값2

WHERE 조건;

서브 쿼리

단일 열/값 

SELECT 칼럼명1, 칼럼명2

FROM 테이블명

WHERE 칼럼명1 in (서브쿼리)

다중열 테이블 

SELECT 서브쿼리명.칼럼명1, 서브쿼리명.컬럼명2

FROM (서브쿼리) 서브쿼리명

 

임시 테이블

view 생성

CREATE VIEW 뷰명

AS (쿼리)

view 삭제

DROP VIEW 뷰명

with 임시 테이블

WITH 임시테이블명 AS(

 임시테이블쿼리

)

임시테이블사용 쿼리

 

사용자 정의 함수

CREATE FUNCTION 함수명 (
 매개변수1,
 매개변수2
) RETURNS 데이터타입
BEGIN
 <SQL 쿼리>;
RETURN 반환값
END;

조인(join)의 종류

테이블을 가로로 합치는 개념

 

inner join

테이블1과 테이블2의 키값이 값을 결과를 리턴

left join

테이블 1 전체와 테이블 2 중 테이블 1과 키 값이 같은 결과를 리턴

빈 곳은 널값이 들어간다.

right join

테이블 2 전체와 테이블 1 중 테이블 2와 키 값이 같은 결과를 리턴

빈 곳은 널값이 들어간다.

SELECT 컬럼명1, 컬럼명2

FROM 테이블명1 JOIN 테이블명2

ON 테이블명1.컬럼A = 테이블명2.컬럼A

 

유니온(union)

테이블을 세로로 합치는 개념

SELECT 칼럼명1 FROM A

UNION  (ALL)      

SELECT 칼럼명1 FROM B

SELECT ID, NAME FROM TABLE1 ;

 UNION

 SELECT ID, NAME FROM TABLE2 ;

 

순위 메기기

순위 함수 설명
rank 중복 순위 적용,
1->2->2->4
dense_rank 중복 순위 적용
1->2->2->3
SELECT 컬럼명, 순위함수() OVER (ORDER BY 컬럼명)

FROM 테이블명

 

이전, 다음 행 조회하기

이동 함수 설명
lag 이전 행
lead 다음 행
SELECT 컬럼명, 이동함수(컬럼명, offset) OVER (ORDER BY 컬럼명)

FROM 테이블명

 

파티션

SELECT 컬럼명, 함수() OVER (PARTITION BY 컬럼명 [ORDER BY 컬럼명])

FROM 테이블명

FRAME절

명령어  설명
current row 현재 로우
n preceding n번째 뒤 로우
n following n번째 앞 로우
unbounded preceding 제일 처음 로우
unbounded following 제일 마지막 로우
SELECT 컬럼명, 함수() OVER (ORDER BY 컬럼명 ROWS BETWEEN [FRAME절] AND [FRAME절])

FROM 테이블명

특정 컬럼 기준으로 그룹화

SELECT 그룹화_칼럼명1, 그룹화_칼럼명2, 집계함수

FROM 테이블명

GROUP BY 그룹화_칼럼명1, 그룹화_칼럼명2

 

그룹화한 칼럼을 기준으로 조건화

SELECT 그룹화_칼럼명1, 그룹화_칼럼명2, 집계함수

FROM 테이블명

GROUP BY 그룹화_칼럼명1, 그룹화_칼럼명2

HAVING 집계함수 조건

+ Recent posts