본문 바로가기

프로그래머스 풀스택 데브코스/데브코스 TIL

웹 풀사이클 데브코스 TIL 37일차

주문하기

Table delivery {
  id integer [primary key]
  address varchar
  receiver varchar
  contact varchar
}

Table orders {
  id integer [primary key]
  delivery_id integer
  book_title varchar
  total_quantity integer
  total_price integer
  created_at timestamp
  user_id integer
}

Table orderedBook {
  id integer [primary key]
  order_id integer
  book_id integer
  quantity integer
}

세 개의 테이블을 사용한다.

테이블 상 delivery 부터 insert 하고 orders insert, 마지막으로 orderedBook insert 해야한다.

주문하기를 위한 SQL 문이다.

// 주문하기
//배송 정보 입력
INSERT INTO deliveries (address, receiver, contact) 
VALUES ('서울시 중구', '김철수', '010-1234-5678')

//주문 정보 입력
INSERT INTO delivery (address, receiver, contact) 
VALUES ('서울시 중구', '김철수', '010-1234-5678')

//주문 상세 목록 입력
INSERT INTO orderedBooks (order_id, book_id, quantity)
VALUES (1, 1, 1);

방금 insert 한 데이터 pk 가져오는 방법

  • LAST_INSERT_ID()
    : 이전 값을 들고오는 오류가 날 수도 있음

  • MAX()
    : 이것을 사용하는게 좋다.

MAX()

max 를 어떻게 사용하면 좋을까? 이는 한가지 예시이다.

INSERT INTO orders (book_title, total_quantity, total_price, user_id, delivery_id)
VALUES ("어린왕자들", 3, 60000, 1, (SELECT max(id) FROM deliveries));

이와 같이 부분 쿼리문으로 사용할 수도 있고

INSERT INTO deliveries (address, receiver, contact) 
VALUES ('서울시 중구', '김철수', '010-1234-5678')
const delivery_id = SELECT max(id) FROM deliveries

INSERT INTO orders (book_title, total_quantity, total_price, user_id, delivery_id)
VALUES ("어린왕자들", 3, 60000, 1, delivery_id);

이와 같이 변수로 뺀후 다시 넣어줄 수도 있다.

하지만 좀 더 편리한 방법도 존재한다

postman 에 result 값을 표시해주고 있다. result 값을 잘 보면 insertId 라는 값이 보이는데 이 값이 우리가 원하는 그 값이다. 따라서 max를 사용해 쿼리를 다시 쳐줄 필요 없이 바로 꺼내서 쓸수 있다.

벌크 INSERT

orderedBook 테이블에 Insert 를 하기 위해서는 items 배열에 있는 책들을 하나하나 꺼내서 SQL문으로 INSERT를 해주어야한다. 이를 위해 items.forEach 문을 사용할 수 있다.

 sql = `INSERT INTO orderedBooks (order_id, book_id, quantity)
    VALUES ?;`;
    values = [];
    items.forEach((item) => {
        values.push([order_id, item.book_id, item.quantity])
    }
    )
    conn.query(sql, [values], (err, results) => {
            if(err) {
                console.log(err);
                return res.status(StatusCodes.INTERNAL_SERVER_ERROR);
            }
            return res.status(StatusCodes.OK).json(results);
        })

하나씩 SQL 문을 쳐서 하는 대신 좋은 방법이 있다. 2차원 배열을 이용하는 것이고 그 배열이 들어갈 자리는 ?로 표시해두는 것이다.

검증 과정

코드의 주석을 풀고 모든 sql문을 한번에 실행시켜보면 새로운 오류가 생긴다.

    conn.query(sql, values, (err, results) => {
         if(err) {
             console.log(err);
             return res.status(StatusCodes.INTERNAL_SERVER_ERROR);
         }

         delivery_id = results.insertId;
         console.log("results.insertId", results.insertId);
         console.log("conn.query - delivery_id", delivery_id);
    })
    console.log("out - delivery_id", delivery_id);

위 코드의 결고 콘솔 로그로는 "results.insertId", "conn.query - delivery_id", "out - delivery_id" 순서로 찍혀야할 것 같지만 실제로는 그렇지 않다.

"out - delivery_id" , "results.insertId", "conn.query - delivery_id" 순서로 찍히게 되고 심지어 conn.query 바깥에서 찍은 로그에서는 delivery_id 가 undefined 로 나온다. 이게 어떻게 된 일 일까?

후기

주문하기 api 를 구현하였고 마지막에 문제점을 아직 남겨두었다.

키워드: 프로그래머스 데브코스, 국비지원교육, 코딩부트캠프