중앙정보기술인재개발원

[중앙정보기술인재개발원] 22일차

기록하는 개발 2024. 5. 3. 16:07

SQL 실습 및 점검

Getting Started

학습 사이트 W3Schools에서 제공하는 Quiz와 Practice를 진행합니다.

Bare minimum requirement

  • 주어진 시간을 활용해 Quiz와 Practice를 모두 완료하세요. 시간 내에 최대한 할 수 있는 만큼만 진행해도 좋습니다. 시간이 부족한 경우, 정규시간 외의 시간을 활용하세요.

Quiz

Quiz 링크

Quiz 링크를 통해 학습 상태를 점검하세요.

Practice

Practice 하러 가기

실제 SQL문을 직접 작성하면서 이해도를 확인하세요.

반드시 스스로 풀어보고, 이해가 안 가는 부분은 다시 학습 내용으로 돌아와서 확인하세요.


과제 - Learn Schema / SQL

Part 1 - 데이터베이스 연결과 스키마

이번 연습문제의 목표는 데이터베이스 연결을 할 수 있고, 주어진 스키마를 구현할 수 있도록 SQL을 작성해야 합니다.

 

Bare minimum requirement

Part_1 테스트를 전부 통과하십시오.

Part1_Test.java 파일을 통해 테스트를 실행할 수 있습니다.

 

Getting Started

1. repository 주소에서 fork 및 clone 후 코드를 작성합니다.

  1. IntelliJ를 실행합니다.
  2. 열기를 클릭한 이후, 다운로드한 폴더를 클릭하고 Open버튼을 클릭합니다.
  3. 신뢰할 수 있는 프로젝트를 클릭합니다.

2. 본인의 MySQL 정보를 입력해 주세요.

script/Properties.java 파일을 확인하고 내 정보를 수정해 주세요.

  1. learnSQL이라는 이름으로 데이터베이스를 만드세요. 앞으로 이 데이터베이스를 사용합니다.
  2. lib/Mysql.java에서 Properties.java 변수가 어떻게 사용되는지 확인해 보세요.
  3. 아래 질문에 고민해 보시고, 페어와 토론해 보세요.
    • 왜 .Properties.java 파일은 .gitignore에 존재할까요?
    • Properties.java 파일이 왜 필요했을지 고민해 보세요.

[주의]

다행히도 여러분들이 직접 데이터베이스 연결 부분을 직접 구현할 필요는 없습니다. 현재 연습문제에서 작성해야 할 데이터베이스 연결 부분은 이미 다 구현되어 있으며, 이후 학습하시는 내용을 통해 직접 연결하는 부분을 작성하게 될 것입니다. 이 시간에는 해당 부분을 전부 이해하려 하기보다는, Properties.java 관련하여 MySQL 정보를 관리하는 방법에 초점을 두고 보시면 됩니다.

 

3. 연습문제 디렉토리

/lib

  • /lib/FactoryService.java
    • FactoryService는 여러분들이 데이터베이스에 연결하여, 원하는 SQL을 작성하여 결과를 확인하는 것과 별개로 TEST가 동작할 수 있도록 도와주는 Class입니다. 구체적으로 해당 연습문제의 동작이 궁금하신 분들만 참고해 주시면 됩니다.
  • /lib/Mysql.java
    • Mysql 서비스에 접속하고 쿼리를 보내는 작업과 자원을 종료하는 동작을 도와주는 Class입니다.

/migrations

  • /schema.sql
    • 이번 연습문제의 핵심이자, 꼭 작성해야 하는 부분입니다. 원하는 테이블과 열을 생성할 수 있어야 합니다.

/model

  • FactoryService가 사용하는 별도의 객체입니다. 해당 객체를 사용하여, 테이블을 조작하게 됩니다.
  • DTO, DAO에 대한 내용은 Section3에서 학습하게 됩니다. 해당 코드를 이해하지 않아도 됩니다.

/script

  • 각 파트에 맞게 SQL STATEMENT를 채워 넣어주세요. 원하는 것을 확인하고, 그에 맞는 SQL을 작성해야 합니다.

그 외 디렉토리

.gitignore 혹은 build.gradle 와 같은 부분은 코드를 보거나 검색을 통해서 이해하실 수 있었으면 합니다.

 

4. migrations/schema.sql을 작성해 주세요.

 

user 테이블 구조

 

content 테이블 구조

  1. 위와 같은 테이블과 열이 필요합니다.
  2. PK는 auto increment 이여야 합니다.
  3. FK를 제외하고는 모두 NOT NULL 이여야 합니다.
  4. created_at과 같은 날짜/시간 정보는 timestamp이면서 default current_timestamp입니다.

[참고4-1] 모든 테스트케이스가 실행되기 전, schema.sql 파일이 실행되고, 끝난 후, database가 삭제된 후 새로 생성됩니다.

lib/FactoryService.java의 setup 메서드를 참고해 주세요.

 

[참고4-2] Schema Visualizer

스키마를 디자인하기 위해 다양한 외부 도구를 사용할 수 있습니다.

5. script/part1.java를 작성하고, Part1_Test의 모든 테스트를 통과하도록 노력하세요.

part1.java의 요구사항을 확인하고, FILL IN THIS를 채워주세요.

 

[참고5-1]

현재 테이블의 결과값을 List와 Map을 활용하여 터미널에 출력하고 있습니다. 실제 Mysql에서 보여주는 결과와 형식이 다를 수 있습니다.

 

[참고5-2]

part1의 경우 연습문제의 구조를 파악하고, schema.sql을 작성하는데 시간을 많이 보내시게 될 것입니다.


Part 2 - 스키마와 함께하는 기본 SQL

Part 2의 목표는 Part 1에서 구성한 스키마에서 데이터를 추가하거나, 불러올 수 있도록 SQL을 작성하는 것을 요구합니다. Learn SQL에서 연습했던 것을 Java 환경에서 다시 한번 확인해 볼 수 있습니다.

 

Bare minimum requirement

Part 2 테스트를 전부 통과하십시오.

Part2_Test.java 파일을 통해 테스트를 실행할 수 있습니다.

 

Getting Started

script/part2.java를 작성하고, Part 2의 모든 테스트를 통과하도록 노력하세요.

아래 사항을 참고하여 진행해 주세요.

  • Part 1의 테스트케이스 역시 통과되어야 합니다.
  • 이번 Part에서는 schema.sql 파일의 변경은 필요하지 않습니다. Learn SQL에서 연습하고 학습한 SQL을 충분히 활용해 보세요.
  • Part 2의 테스트에서는 아래 표와 같이 데이터가 존재합니다. 이는 아래의 도표가 아닌, 테스트케이스를 살펴보아도 알 수 있습니다. (lib/FactoryService.java의 58번째 줄 part2_setup 메서드를 참고해 주세요.)

user 테이블 데이터

content 테이블 데이터


Part 3 - 추가 요구조건과 스키마

Part 3의 목표는 추가 요구조건에 따라, 스키마를 추가/변경하고 이를 확인해 보는 과정입니다. 이를 통해 1:N, N:N 관계와 더불어 JOIN에 대한 이해가 단단해 지기를 기대합니다.

 

Bare minimum requirement

Part 3 테스트를 전부 통과하십시오.

  • Part3_Test.java 파일을 통해 테스트를 실행할 수 있습니다.
  • Part 1, Part 2 테스트 또한 모두 통과해야 합니다.

Getting Started

1. migrations/schema.sql을 추가 작성해 주세요.

content 테이블

변경사항이 없습니다.

 

category 테이블 구조

 

content_category 테이블 구조

 

role 테이블 구조

 

user 테이블 구조

2. script/part3.java에 주석을 참고하여, SQL을 채워 넣어주세요.

  • 참고: part3의 테스트에서는 테스트케이스를 살펴보고, 확인해 보세요. (lib/FactoryService.java의 112번째 줄 part3_setup 메서드를 참고해 주세요.)

Part 3의 목표는 추가 요구조건에 따라, 스키마를 추가/변경하고 이를 확인해 보는 과정입니다. 이를 통해 1:N, N:N 관계와 더불어 JOIN에 대한 이해가 단단해 지기를 기대합니다.


Properties

package com.codestates.script;

public class Properties {
  public static String URL = "jdbc:mysql://127.0.0.1:3306"; // 기본 설정값
  public static String DATABASE_USERNAME = "root"; // 기본값은 root입니다.
  public static String DATABASE_PASSWORD = "****"; // 본인의 패스워드로 변경해주세요.

  public static String getURL() {
    return URL;
  }

  public static String getDatabaseUsername() {
    return DATABASE_USERNAME;
  }

  public static String getDatabasePassword() {
    return DATABASE_PASSWORD;
  }
}

 

schema.sql

CREATE TABLE `role` (
  `id` int PRIMARY KEY AUTO_INCREMENT,
  `name` varchar(255) not NULL
);

CREATE TABLE `user` (
  `id` int PRIMARY KEY AUTO_INCREMENT,
  `name` varchar(255) not NULL,
  `email` varchar(255) not NULL,
  `roleId` int,
  FOREIGN KEY (`roleId`) REFERENCES `role` (`id`)
);

CREATE TABLE `content` (
  `id` int PRIMARY KEY AUTO_INCREMENT,
  `title` varchar(255),
  `body` varchar(255),
  `created_at` timestamp not NULL DEFAULT CURRENT_TIMESTAMP,
  `userId` int,
  FOREIGN KEY (`userId`) REFERENCES `user` (`id`)
);

CREATE TABLE `category` (
  `id` int PRIMARY KEY AUTO_INCREMENT,
  `name` varchar(255) not NULL
);

CREATE TABLE `content_category` (
  `id` int PRIMARY KEY AUTO_INCREMENT,
  `contentId` int not NULL,
  `categoryId` int not NULL,
  FOREIGN KEY (`contentId`) REFERENCES `content` (`id`),
  FOREIGN KEY (`categoryId`) REFERENCES `category` (`id`)
);

 

part1

package com.codestates.script;

public class part1 {
  /*
  ----------------------------------------------------------------------------------------------
      TODO: 유어클래스의 requirement를 참조하여, migration/schema.sql에 알맞은 테이블을 구성해주세요.
  */

  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 1-1. 현재 있는 데이터베이스에 존재하는 모든 테이블 정보를 보기위한 SQL을 작성해주세요.
  */
  public static final String PART1_1 = "SHOW TABLES";

  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 1-2. user 테이블의 구조를 보기위한 SQL을 작성해주세요.
          - 요구사항에 맞는 user 테이블을 작성해야만, 테스트를 통과합니다.
  */
  public static final String PART1_2 = "DESC user";

  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 1-3. content 테이블의 구조를 보기위한 SQL을 작성해주세요.
          - 요구사항에 맞는 content 테이블을 작성해야만, 테스트를 통과합니다.
  */
  public static final String PART1_3 = "DESC content";

}

 

 

part1 test code

package com.codestates;

import com.codestates.lib.FactoryService;
import com.codestates.lib.Mysql;
import com.codestates.script.Properties;
import com.codestates.script.part1;
import org.junit.jupiter.api.*;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;

import static org.assertj.core.api.Assertions.assertThat;

public class Part1_Test {

  private static Mysql mysql = Mysql.getInstance();
  private static FactoryService factoryService = FactoryService.getInstance();
  private static Connection connection = null;

  // 테스트 시작전 initializr
  @BeforeAll
  public static void init() throws SQLException {
    connection = mysql.getConnection();
    factoryService.init(connection);
    factoryService.migration(connection);
  }

  // 테스트 종료후 데이터베이스 자원 종료
  @AfterAll
  public static void terminate() throws SQLException {
    mysql.terminate(connection);
  }

  @Test
  @DisplayName("Q 1-0. 데이터베이스 접속 확인")
  public void Connect_Test() throws SQLException {
    System.out.printf("<YOUR DATABASE CONFIG>%n");
    System.out.printf("URL : %s%n", com.codestates.script.Properties.getURL());
    System.out.printf("DATABASE_USERNAME : %s%n", Properties.getDatabaseUsername());
    System.out.printf("DATABASE_PASSWORD : %s%n", com.codestates.script.Properties.getDatabasePassword());
  }

  @Test
  @DisplayName("Q 1-1. 현재 있는 데이터베이스에 존재하는 모든 테이블 정보를 보기위한 SQL을 작성해주세요.")
  public void Query_Test_1_1() throws SQLException {
    ArrayList<HashMap<String,Object>> response = mysql.selectQuery(connection, part1.PART1_1);
    assertThat(response.size() >= 2).isTrue();

    assertThat(response.toString().contains("user")).isTrue();
    assertThat(response.toString().contains("content")).isTrue();

    // 결과 출력
    for(HashMap<String, Object> map: response) {
      Set set = map.entrySet();
      for (Object o : set) {
        Map.Entry<String, Object> entry = (Map.Entry) o;
        Object value = entry.getValue();
        System.out.printf("TABLE : %s%n", value);
      }
    }
  }

  @Test
  @DisplayName("Q 1-2. user 테이블의 구조를 보기위한 SQL을 작성해주세요.")
  public void Query_Test_1_2() throws SQLException {
    ArrayList<HashMap<String,Object>> response = mysql.selectQuery(connection, part1.PART1_2);

    assertThat(response.size() >= 3).isTrue();

    assertThat(response.get(0).toString().contains("id")).isTrue();
    assertThat(response.get(0).toString().contains("PRI")).isTrue();
    assertThat(response.get(1).toString().contains("name")).isTrue();
    assertThat(response.get(1).toString().contains("varchar")).isTrue();
    assertThat(response.get(2).toString().contains("email")).isTrue();

    // 결과 출력
    for(HashMap<String, Object> map: response) {
      System.out.println(map);
    }
  }

  @Test
  @DisplayName("Q 1-3. content 테이블의 구조를 보기위한 SQL을 작성해주세요.")
  public void Query_Test_1_3() throws SQLException {
    ArrayList<HashMap<String,Object>> response = mysql.selectQuery(connection, part1.PART1_3);

    assertThat(response.size()).isEqualTo(5);

    assertThat(response.get(0).toString().contains("id")).isTrue();
    assertThat(response.get(0).toString().contains("PRI")).isTrue();
    assertThat(response.get(1).toString().contains("title")).isTrue();
    assertThat(response.get(1).toString().contains("varchar")).isTrue();
    assertThat(response.get(2).toString().contains("body")).isTrue();
    assertThat(response.get(3).toString().contains("created_at")).isTrue();
    assertThat(response.get(3).toString().contains("CURRENT_TIMESTAMP")).isTrue();
    assertThat(response.get(4).toString().contains("userId")).isTrue();
    assertThat(response.get(4).toString().contains("MUL")).isTrue();

    // 결과 출력
    for(HashMap<String, Object> map: response) {
      System.out.println(map);
    }
  }
}

 

part2

package com.codestates.script;

public class part2 {
  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 2-1. user 테이블에 존재하는 모든 컬럼을 포함한 모든 데이터를 확인하기 위한 SQL을 작성해주세요.
  */
  public static final String PART2_1 = "SELECT * FROM user";

  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 2-2. user 테이블에 존재하는 모든 데이터에서 name 컬럼만을 확인하기 위한 SQL을 작성해주세요.
  */
  public static final String PART2_2 = "SELECT name FROM user";

  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 2-3. user 테이블에 데이터를 추가하기 위한 SQL을 작성해주세요.
          - 원하는 name, email을 사용하시면 됩니다.
  */
  public static final String PART2_3 = "INSERT INTO user(name, email) VALUES('midsummer','midsummer@naver.com')";

  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 2-4. user 테이블에서 특정 조건을 가진 데이터를 찾기위한 SQL을 작성해주세요.
          - 조건 : name이 luckykim이여야 합니다.
  */
  public static final String PART2_4 = "SELECT * FROM user WHERE name = 'luckykim'";

  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 2-5. user 테이블에서 특정 조건을 가진 데이터를 찾기위한 SQL을 작성해주세요.
          - 조건 : name이 luckykim이 아니여야 합니다.
  */
  public static final String PART2_5 = "SELECT name FROM user WHERE name <> 'luckykim'";

  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 2-6. content 테이블에 존재하는 모든 데이터에서 title 컬럼만을 찾기 위한 SQL을 작성해주세요.
  */

  public static final String PART2_6 = "SELECT title FROM content";

  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 2-7. content의 title과 그 컨텐츠를 작성한 user의 name을 찾기 위한 SQL을 작성해주세요.
          - 저자가 없더라도, 켄턴츠의 title을 모두 찾아야합니다.
  */
  public static final String PART2_7 = "SELECT title, name FROM content LEFT JOIN user ON user.id = content.id";

  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 2-8. content의 title과 그 컨텐츠를 작성한 user의 name을 찾기 위한 SQL을 작성해주세요.
          - 저자가 있는 컨텐츠의 title만 찾아야합니다.
  */
  public static final String PART2_8 = "SELECT content.title, user.name FROM content JOIN user ON user.id = content.userId";

  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 2-9. content의 데이터를 수정하기 위한 SQL을 작성해주세요.
          - title이 database homework인 content 데이터에서 body를 database is very easy로 수정해야합니다.
  */
  public static final String PART2_9 = "UPDATE content SET content.body = 'database is  very easy' WHERE content.title = 'database homework'";

  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 2-10. content의 데이터를 추가하기 위한 SQL을 작성해주세요.
          - luckykim이 작성한 컨텐츠를 추가해주세요. 제목과 본문은 자유입니다. (참고: luckykim의 아이디는 1입니다.)
  */
  public static final String PART2_10 = "INSERT INTO content(title, body, userId) VALUES('ab', 'cd', 1)";
}

 

part2 test code

package com.codestates;

import com.codestates.lib.FactoryService;
import com.codestates.lib.Mysql;
import com.codestates.script.part2;
import org.junit.jupiter.api.*;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;

import static org.assertj.core.api.Assertions.assertThat;

public class Part2_Test {
  private static final Mysql mysql = Mysql.getInstance();
  private static final FactoryService factoryService = FactoryService.getInstance();
  private static Connection connection = null;

  @BeforeAll
  public static void init() throws SQLException {
    connection = mysql.getConnection();
    factoryService.init(connection);
    factoryService.migration(connection);
    factoryService.part2_setup();
  }

  @AfterAll
  public static void terminate() throws SQLException {
    mysql.terminate(connection);
  }

  @Test
  @DisplayName("Q 2-1. user 테이블에 존재하는 모든 컬럼을 포함한 모든 데이터를 확인하기 위한 SQL을 작성해주세요.")
  public void Query_Test_2_1() throws SQLException {
    ArrayList<HashMap<String,Object>> response = mysql.selectQuery(connection, part2.PART2_1);
    ArrayList<HashMap<String,Object>> factoryResponse = factoryService.find(connection, "user", "*");

    assertThat(response.size()).isEqualTo(4);
    assertThat(response).usingRecursiveComparison().isEqualTo(factoryResponse);
  }

  @Test
  @DisplayName("Q 2-2. user 테이블에 존재하는 모든 데이터에서 name 컬럼만을 확인하기 위한 SQL을 작성해주세요.")
  public void Query_Test_2_2() throws SQLException {
    ArrayList<HashMap<String,Object>> response = mysql.selectQuery(connection,part2.PART2_2);
    ArrayList<HashMap<String,Object>> factoryResponse = factoryService.find(connection, "user", "name");

    assertThat(response.size()).isEqualTo(4);
    assertThat(response).usingRecursiveComparison().isEqualTo(factoryResponse);
  }

  @Test
  @DisplayName("Q 2-3. user 테이블에 데이터를 추가하기 위한 SQL을 작성해주세요.")
  public void Query_Test_2_3() throws SQLException {
    mysql.query(connection,part2.PART2_3);
    ArrayList<HashMap<String,Object>> factoryResponse = factoryService.find(connection, "user", "*");

    assertThat(factoryResponse.size()).isEqualTo(5);
  }

  @Test
  @DisplayName("Q 2-4. user 테이블에서 특정 조건을 가진 데이터를 찾기위한 SQL을 작성해주세요.")
  public void Query_Test_2_4() throws SQLException {
    ArrayList<HashMap<String,Object>> response = mysql.selectQuery(connection,part2.PART2_4);

    System.out.println(response);
    assertThat(response.size()).isEqualTo(1);
    assertThat(response.get(0).get("name")).isEqualTo("luckykim");
  }

  @Test
  @DisplayName("Q 2-5. user 테이블에서 특정 조건을 가진 데이터를 찾기위한 SQL을 작성해주세요.")
  public void Query_Test_2_5() throws SQLException {
    ArrayList<HashMap<String,Object>> response = mysql.selectQuery(connection,part2.PART2_5);

    assertThat(response.size()).isBetween(3, 4);
    for(HashMap<String, Object> data : response) {
      assertThat(data.get("name")).isNotEqualTo("luckykim");
    }
  }

  @Test
  @DisplayName("Q 2-6. content 테이블에 존재하는 모든 데이터에서 title 컬럼만을 찾기 위한 SQL을 작성해주세요.")
  public void Query_Test_2_6() throws SQLException {
    ArrayList<HashMap<String,Object>> response = mysql.selectQuery(connection,part2.PART2_6);
    ArrayList<HashMap<String,Object>> factoryResponse = factoryService.find(connection, "content", "title");

    assertThat(factoryResponse.size()).isEqualTo(3);
    assertThat(response).usingRecursiveComparison().isEqualTo(factoryResponse);
  }

  @Test
  @DisplayName("Q 2-7. content의 title과 그 컨텐츠를 작성한 user의 name을 찾기 위한 SQL을 작성해주세요. - 저자가 없더라도, 켄턴츠의 title을 모두 찾아야합니다.")
  public void Query_Test_2_7() throws SQLException {
    ArrayList<HashMap<String,Object>> response = mysql.selectQuery(connection,part2.PART2_7);

    assertThat(response.size()).isEqualTo(3);
    int count = 0;
    for(HashMap<String, Object> data : response) {
      if(data.get("name") == null) continue;
      if(data.get("name").equals("luckykim")) count++;
    }

    assertThat(count).isEqualTo(1);
  }

  @Test
  @DisplayName("Q 2-8. content의 title과 그 컨텐츠를 작성한 user의 name을 찾기 위한 SQL을 작성해주세요. - 저자가 있는 컨텐츠의 title만 찾아야합니다.")
  public void Query_Test_2_8() throws SQLException {
    ArrayList<HashMap<String,Object>> response = mysql.selectQuery(connection,part2.PART2_8);

    assertThat(response.size()).isEqualTo(1);
    assertThat(response.get(0).get("title")).isEqualTo("database homework");
    assertThat(response.get(0).get("name")).isEqualTo("luckykim");
  }

  @Test
  @DisplayName("Q 2-9. content의 데이터를 수정하기 위한 SQL을 작성해주세요. - title이 database homework인 content 데이터에서 body를 database is very easy로 수정해야합니다.")
  public void Query_Test_2_9() throws SQLException {
    mysql.query(connection,part2.PART2_9);
    ArrayList<HashMap<String,Object>> factoryResponse = factoryService.find(connection, "content", "*");

    assertThat(factoryResponse.size()).isEqualTo(3);

    for(HashMap<String, Object> data : factoryResponse) {
      assertThat(data.get("body")).isNotEqualTo("database is easy");
    }
  }

  @Test
  @DisplayName("Q 2-10. content의 데이터를 추가하기 위한 SQL을 작성해주세요. - luckykim이 작성한 컨텐츠를 추가해주세요. 제목과 본문은 자유입니다. (참고: luckykim의 아이디는 1입니다.)")
  public void Query_Test_2_10() throws SQLException {
    mysql.query(connection,part2.PART2_10);
    ArrayList<HashMap<String,Object>> factoryResponse = factoryService.find(connection, "content", "*");

    assertThat(factoryResponse.size()).isEqualTo(4);
    int count = 0;
    for(HashMap<String, Object> data : factoryResponse) {
      if(data.get("userId") == null) continue;
      int userId = (int)data.get("userId");
      if(userId == 1) count++;
    }
    assertThat(count).isEqualTo(2);
  }
}

 

part3

package com.codestates.script;

public class part3 {
  /*
  ----------------------------------------------------------------------------------------------
      TODO: 유어클래스의 requirement를 참조하여, migration/schema.sql에 추가로 구성해주세요.
  */

  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 3-1-1. category 테이블의 구조를 보기위한 SQL을 작성해주세요.
          - 요구사항에 맞는 category 테이블을 작성해야만, 테스트를 통과합니다.
  */
  public static final String PART3_1_1 = "DESC category";

  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 3-1-2. content_category 테이블의 구조를 보기위한 SQL을 작성해주세요.
          - 요구사항에 맞는 content_category 테이블을 작성해야만, 테스트를 통과합니다.
  */
  public static final String PART3_1_2 = "DESC content_category";

  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 3-1-3. role 테이블의 구조를 보기위한 SQL을 작성해주세요.
          - 요구사항에 맞는 role 테이블을 작성해야만, 테스트를 통과합니다.
  */
  public static final String PART3_1_3 = "DESC role";

  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 3-1-4. user 테이블의 구조를 보기위한 SQL을 작성해주세요.
          - 요구사항에 맞는 user 테이블을 작성해야만, 테스트를 통과합니다.
  */
  public static final String PART3_1_4 = "DESC user";

  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 3-2-1. category 테이블에 존재하는 데이터에서 id, name을 찾는 SQL을 작성해주세요.
  */

  public static final String PART3_2_1 = "SELECT id, name FROM category";

  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 3-2-2. user의 name과 email 그리고 그 user가 속한 role name(컬럼명: roleName)을 찾기 위한 SQL을 작성해주세요.
          - 속한 role이 없더라도, user의 name과 email,role name을 모두 찾아야합니다.
  */
  public static final String PART3_2_2 = "SELECT user.name, user.email, role.name AS roleName FROM user LEFT JOIN role ON user.roleId = role.id";

  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 3-2-3. 어느 role에도 속하지 않는 user의 모든 컬럼 데이터를 찾기위한 SQL을 작성해주세요.
  */
  public static final String PART3_2_3 = "SELECT * FROM user WHERE user.roleId IS NULL";

  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 3-2-4. content_category 테이블에 존재하는 모든 칼럼의 데이터를 찾기위한 SQL을 작성해주세요.
  */
  public static final String PART3_2_4 = "SELECT * FROM content_category";

  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 3-2-5. minsanggu이 작성한 content의 title을 찾기위한 SQL을 작성해주세요.
  */
  public static final String PART3_2_5 = "SELECT content.title FROM content JOIN user ON content.userId = user.id WHERE user.name = 'minsanggu'";

  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 3-2-6. minsanggu이 작성한 content의 category name을 찾기위한 SQL을 작성해주세요.
  */
  public static final String PART3_2_6 = "SELECT category.name FROM category JOIN content_category ON category.id = content_category.categoryId JOIN content ON content_category.contentId = content.id JOIN user ON content.userId = user.id WHERE user.name = 'minsanggu'";

  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 3-2-7. category의 name이 java인 content의 title, body, created_at을 찾기위한 SQL을 작성해주세요.
  */
  public static final String PART3_2_7 = "SELECT content.title, content.body, content.created_at FROM content JOIN content_category ON content.id = content_category.contentId JOIN category ON content_category.categoryId = category.id WHERE category.name = 'java'";

  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 3-2-8. category의 name이 java인 content의 title, body, created_at, user의 name을 찾기위한 SQL을 작성해주세요.
  */
  public static final String PART3_2_8 = "SELECT content.title, content.body, content.created_at, user.name FROM content JOIN content_category ON content.id = content_category.contentId JOIN category ON content_category.categoryId = category.id JOIN user ON content.userId = user.id WHERE category.name = 'java'";

  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 3-2-9. teawoongna가 작성한 글의 개수 (컬럼명: ContentCount)를 출력하기 위한 SQL을 작성해주세요.
  */
  public static final String PART3_2_9 = "SELECT COUNT(*) AS ContentCount FROM content JOIN user ON content.userId = user.id WHERE user.name = 'teawoongna'";

  /*
  ----------------------------------------------------------------------------------------------
      TODO: Q 3-2-10. 각 user(컬럼명: name)가 작성한 글의 개수 (컬럼명: ContentCount)를 출력하기 위한 SQL을 작성해주세요.
  */
  public static final String PART3_2_10 = "SELECT user.name AS name, COUNT(content.id) AS ContentCount FROM content RIGHT JOIN user ON content.userId = user.id GROUP BY user.name";
}

 

part3 test code

package com.codestates;

import com.codestates.lib.FactoryService;
import com.codestates.lib.Mysql;
import com.codestates.script.part3;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;

import static org.assertj.core.api.Assertions.assertThat;

public class Part3_Test {
  private static final Mysql mysql = Mysql.getInstance();
  private static final FactoryService factoryService = FactoryService.getInstance();
  private static Connection connection = null;

  @BeforeAll
  public static void init() throws SQLException {
    connection = mysql.getConnection();
    factoryService.init(connection);
    factoryService.migration(connection);
    factoryService.part3_setup();
  }

  @AfterAll
  public static void terminate() throws SQLException {
    mysql.terminate(connection);
  }

  @Test
  @DisplayName("Q 3-1-1. category 테이블의 구조를 보기위한 SQL을 작성해주세요.")
  public void Query_Test_3_1_1() throws SQLException {
    ArrayList<HashMap<String,Object>> response = mysql.selectQuery(connection, part3.PART3_1_1);

    assertThat(response.size()).isEqualTo(2);

    assertThat(response.get(0).toString().contains("id")).isTrue();
    assertThat(response.get(0).toString().contains("PRI")).isTrue();
    assertThat(response.get(0).toString().contains("auto_increment")).isTrue();
    assertThat(response.get(1).toString().contains("name")).isTrue();
    assertThat(response.get(1).toString().contains("varchar")).isTrue();

    // 결과 출력
    for(HashMap<String, Object> map: response) {
      System.out.println(map);
    }
  }

  @Test
  @DisplayName("Q 3-1-2. content_category 테이블의 구조를 보기위한 SQL을 작성해주세요.")
  public void Query_Test_3_1_2() throws SQLException {
    ArrayList<HashMap<String,Object>> response = mysql.selectQuery(connection, part3.PART3_1_2);

    System.out.println(response);
    assertThat(response.size()).isEqualTo(3);

    assertThat(response.get(0).toString().contains("id")).isTrue();
    assertThat(response.get(0).toString().contains("PRI")).isTrue();
    assertThat(response.get(0).toString().contains("auto_increment")).isTrue();
    assertThat(response.get(1).toString().contains("contentId")).isTrue();
    assertThat(response.get(1).toString().contains("MUL")).isTrue();
    assertThat(response.get(2).toString().contains("categoryId")).isTrue();
    assertThat(response.get(2).toString().contains("MUL")).isTrue();

    // 결과 출력
    for(HashMap<String, Object> map: response) {
      System.out.println(map);
    }
  }

  @Test
  @DisplayName("Q 3-1-3. role 테이블의 구조를 보기위한 SQL을 작성해주세요.")
  public void Query_Test_3_1_3() throws SQLException {
    ArrayList<HashMap<String,Object>> response = mysql.selectQuery(connection, part3.PART3_1_3);

    assertThat(response.size()).isEqualTo(2);

    assertThat(response.get(0).toString().contains("id")).isTrue();
    assertThat(response.get(0).toString().contains("PRI")).isTrue();
    assertThat(response.get(0).toString().contains("auto_increment")).isTrue();
    assertThat(response.get(1).toString().contains("name")).isTrue();
    assertThat(response.get(1).toString().contains("varchar")).isTrue();


    // 결과 출력
    for(HashMap<String, Object> map: response) {
      System.out.println(map);
    }
  }

  @Test
  @DisplayName("Q 3-1-4. user 테이블의 구조를 보기위한 SQL을 작성해주세요.")
  public void Query_Test_3_1_4() throws SQLException {
    ArrayList<HashMap<String,Object>> response = mysql.selectQuery(connection, part3.PART3_1_4);

    assertThat(response.size()).isEqualTo(4);

    assertThat(response.get(0).toString().contains("id")).isTrue();
    assertThat(response.get(0).toString().contains("PRI")).isTrue();
    assertThat(response.get(0).toString().contains("auto_increment")).isTrue();
    assertThat(response.get(1).toString().contains("name")).isTrue();
    assertThat(response.get(1).toString().contains("varchar")).isTrue();
    assertThat(response.get(2).toString().contains("email")).isTrue();
    assertThat(response.get(2).toString().contains("varchar")).isTrue();
    assertThat(response.get(3).toString().contains("roleId")).isTrue();
    assertThat(response.get(3).toString().contains("MUL")).isTrue();

    // 결과 출력
    for(HashMap<String, Object> map: response) {
      System.out.println(map);
    }
  }

  @Test
  @DisplayName("Q 3-2-1. category 테이블에 존재하는 데이터에서 id, name을 찾는 SQL을 작성해주세요.")
  public void Query_Test_3_2_1() throws SQLException {
    ArrayList<HashMap<String,Object>> response = mysql.selectQuery(connection, part3.PART3_2_1);

    assertThat(response.size()).isEqualTo(3);
    for(HashMap<String, Object> map: response) {
      assertThat(map.size()).isEqualTo(2);
      System.out.println(map);
    }
  }

  @Test
  @DisplayName("Q 3-2-2. user의 name과 email 그리고 그 user가 속한 role name(컬럼명: roleName)을 찾기 위한 SQL을 작성해주세요. - 속한 role이 없더라도, user의 name과 email,role name을 모두 찾아야합니다.")
  public void Query_Test_3_2_2() throws SQLException {
    ArrayList<HashMap<String,Object>> response = mysql.selectQuery(connection, part3.PART3_2_2);

    assertThat(response.size()).isEqualTo(5);

    int count = 0;

    for(HashMap<String, Object> map: response) {
      assertThat(map.size()).isEqualTo(3);
      if(map.get("roleName") == null) count++;
    }
    assertThat(count).isEqualTo(1);
  }

  @Test
  @DisplayName("Q 3-2-3. 어느 role에도 속하지 않는 user의 모든 컬럼 데이터를 찾기위한 SQL을 작성해주세요.")
  public void Query_Test_3_2_3() throws SQLException {
    ArrayList<HashMap<String,Object>> response = mysql.selectQuery(connection, part3.PART3_2_3);

    assertThat(response.size()).isEqualTo(1);
    assertThat(response.get(0).get("roleId")).isNull();
    assertThat(response.get(0).get("name")).isEqualTo("jungsikhwang");
  }

  @Test
  @DisplayName("Q 3-2-4. content_category 테이블에 존재하는 모든 칼럼의 데이터를 찾기위한 SQL을 작성해주세요.")
  public void Query_Test_3_2_4() throws SQLException {
    ArrayList<HashMap<String,Object>> response = mysql.selectQuery(connection, part3.PART3_2_4);

    assertThat(response.size()).isEqualTo(4);
    for(HashMap<String, Object> map: response) {
      assertThat(map.size()).isEqualTo(3);
    }
  }

  @Test
  @DisplayName("Q 3-2-5. minsanggu이 작성한 content의 title을 찾기위한 SQL을 작성해주세요.")
  public void Query_Test_3_2_5() throws SQLException {
    ArrayList<HashMap<String,Object>> response = mysql.selectQuery(connection, part3.PART3_2_5);

    assertThat(response.size()).isEqualTo(1);
    assertThat(response.get(0).get("title")).isEqualTo("developer proverb");
  }

  @Test
  @DisplayName("Q 3-2-6. minsanggu이 작성한 content의 category name을 찾기위한 SQL을 작성해주세요.")
  public void Query_Test_3_2_6() throws SQLException {
    ArrayList<HashMap<String,Object>> response = mysql.selectQuery(connection, part3.PART3_2_6);

    System.out.println(response);
    assertThat(response.size()).isEqualTo(2);
    assertThat(response.get(0).get("name")).isEqualTo("java");
    assertThat(response.get(1).get("name")).isEqualTo("query");
  }

  @Test
  @DisplayName("Q 3-2-7. category의 name이 java인 content의 title, body, created_at을 찾기위한 SQL을 작성해주세요.")
  public void Query_Test_3_2_7() throws SQLException {
    ArrayList<HashMap<String,Object>> response = mysql.selectQuery(connection, part3.PART3_2_7);

    assertThat(response.size()).isEqualTo(2);
    assertThat(response.get(0).get("title")).isEqualTo("developer proverb");
    assertThat(response.get(1).get("title")).isEqualTo("common proverb");
  }

  @Test
  @DisplayName("Q 3-2-8. category의 name이 java인 content의 title, body, created_at, user의 name을 찾기위한 SQL을 작성해주세요.")
  public void Query_Test_3_2_8() throws SQLException {
    ArrayList<HashMap<String,Object>> response = mysql.selectQuery(connection, part3.PART3_2_8);

    assertThat(response.size()).isEqualTo(2);
    assertThat(response.get(0).get("title")).isEqualTo("developer proverb");
    assertThat(response.get(0).get("name")).isEqualTo("minsanggu");
    assertThat(response.get(0).size()).isEqualTo(4);
    assertThat(response.get(1).get("title")).isEqualTo("common proverb");
    assertThat(response.get(1).get("name")).isEqualTo("teawoongna");
    assertThat(response.get(1).size()).isEqualTo(4);
  }

  @Test
  @DisplayName("Q 3-2-9. teawoongna가 작성한 글의 개수 (컬럼명: ContentCount)를 출력하기 위한 SQL을 작성해주세요.")
  public void Query_Test_3_2_9() throws SQLException {
    ArrayList<HashMap<String,Object>> response = mysql.selectQuery(connection, part3.PART3_2_9);

    assertThat(response.size()).isEqualTo(1);
    assertThat(response.get(0).get("ContentCount")).isEqualTo(1L);
  }

  @Test
  @DisplayName("Q 3-2-10. 각 user(컬럼명: name)가 작성한 글의 개수 (컬럼명: ContentCount)를 출력하기 위한 SQL을 작성해주세요.")
  public void Query_Test_3_2_10() throws SQLException {
    ArrayList<HashMap<String,Object>> response = mysql.selectQuery(connection, part3.PART3_2_10);

    assertThat(response.size()).isEqualTo(5);
    int count = 0;
    for(HashMap<String, Object> map: response) {
      assertThat(map.size()).isEqualTo(2);
      if(map.get("ContentCount").toString().equals("1")) count++;
    }
    assertThat(count).isEqualTo(2);
  }
}