s e o p p o r t . l o g

Today I Learned

[클룸] 클래스의 세션별로 데이터 관리하기 - 테이블 조인을 활용한 예약 정보 불러오기

Seo Ji Won 2024. 4. 9. 22:42

++ 이전글

https://seopport-u.tistory.com/87

 

Supabase에서의 테이블 간 조인과 외래 키 관계

Supabase는 PostgreSQL을 기반으로 하며, 데이터베이스 스키마에 정의된 외래 키 관계를 활용하여 테이블 간의 관계를 쉽게 조인할 수 있다. 이를 통해 sql editor로 직접 쿼리를 작성하지 않고도 원하는 데이터를 조인해서 가져올 수 있다.

 

다음과 같이 테이블이 설계되어있다고 해보자

DB ERD

reserve테이블과 class테이블은 class_id로 연결되어있고,

date테이블은 class_id로 class 테이블과 연결되어있다.

reserve테이블과 time테이블은 time_id로 연결되어있다. (time_id는 각 클래스의 하나의 세션의 고유값)

time테이블은 date_id로 date테이블과 연결되어있다.

설계한 ERD를 바탕으로 예약정보의 클래스 정보, 시간, 일자를 받아오기 위한 과정은 다음과 같다.

  1. 클래스 정보 조인:
    • 예약 정보의 **class_id**를 사용하여 class 테이블과 조인하고, 예약된 클래스의 title, total_time, location 정보를 가져옵니다.
  2. 시간 정보 조인:
    • 예약 정보의 time_id를 사용하여 time 테이블과 조인하고, 예약된 시간(times) 정보를 가져옵니다.
  3. 일자 정보 조인:
    • time 테이블에서 가져온 **date_id**를 사용하여 date 테이블과 조인하고, 해당하는 일자의 day 정보를 가져옵니다.

 

이 함수는 reserve id를 인자로 받아 reserve 테이블과 class, time, date 테이블을 조인해서 해당하는 예약 정보를 불러오는 함수이다.

export const fetchReservationDetails = async (reserveId: string) => {
  const { data, error }: PostgrestSingleResponse<DBReservationDetailsType> = await supabase
    .from('reserve')
    .select(
      `
        class_id, reserve_quantity, reserve_price, time_id, user_id,
        class(title, total_time, location),
        time (times, date(day))
  `
    )
    .eq('reserve_id', reserveId)
    .single();


  if (error) {
    console.log('fetchReservationDetails error =>', error);
    return;
  }
  
  return data;
  };

select 절을 해석해보자면

1. reserve 테이블과 class테이블을 class_id로 inner 조인하여 예약하는 클래스의 정보의 title, total_time, location을 가져온다.

2. reserve 테이블과 time테이블을 time_id로 inner 조인하여 times(예약 시간)를 불러온다. 

3. time테이블과 date테이블을 date_id로 inner 조인하여 day(예약 일자)를 불러온다.

 

inner 조인 = 교집합

supabase는 조인할 테이블에서 선택할 컬럼을 입력할 때 외래키로 설정되어있는 아이디를 적어주지 않아도 스키마에서 정의한 외래 키 관계를 기반으로 하여 쿼리 시점에 명시된 테이블 간의 관계를 감지하고 적절히 조인(join)하여 결과를 반환해준다. (나의 경우 class_id, time_id가 필요해서 select절에 적어주었지만 id가 필요하지 않다면 적어주지 않아도 알아서 외래키 관계를 감지해서 조인한다)

 

 .select(
      `
        class_id, reserve_quantity, reserve_price, time_id, user_id,
        class(title, total_time, location),
        time (times, date(day))
  `

reserve 테이블과 class 테이블은 class_id로 연결되어있기 때문에

reserve테이블과 class 테이블에서 class_id가 일치하는 행을 찾아서 join해서 반환해준다는 것이다.

 

함수의 반환값은 다음과 같이 출력된다.

함수 실행 결과값

 

😊 결론

관계형 데이터베이스에 적합한 설계를 통해 각 테이블이 독립적인 역할을 할 수 있도록 하고, 외래 키 관계로 연결되도록 하여 데이터의 무결성을 지킬 수 있었다.

또한 이 경험을 통해 초기 설계의 중요성을 깊이 느꼈다. 철저한 초기 분석과 설계는 나중에 발생할 수 있는 많은 문제를 예방할 수 있다는 것을 배웠다.