전체 글 (135)

728x90

 

수업내용 정리 (Java)

 

1. 수업일지 29일차 1-3 문제 변형

로그인할때 틀리면 계속 입력을 받아서 로그인에 성공하면 멈추도록 하기(boolean으로 반환받기)
위와 동일하지만 boolean이 아니라 Member 변수로 반환받기로 변형

 1-1) 메인 ㄱ 

더보기
import java.util.Scanner;
import been.Member;
import service.MemberService;

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		// 회원서비스 비지니스로직(업무코드)
		MemberService mSer = new MemberService();
		while(true) {
			System.out.print(" 아이디 입력> ");
			String id = sc.next();
			System.out.print(" 비밀번호 입력> ");
			String pw = sc.next();
			Member member = mSer.login(id, pw);
			if(member != null) {
				System.out.println(" > "+id+"님의 회원정보");
				member.showInfo();
				break;
			}else {
				System.out.println(" > id 또는 pw가 틀렸습니다.\n");
			}
		}
		System.out.println(" > 프로그램 종료");
	}
}
  • member가 null일 경우를 대비하여 if문을 입력하였다.

 

 1-2) Member 클래스 ㄱ 

더보기
public class Member {
	private String id;
	private String pw;
	private String name;
	private int age;
	private String birth;
	
	public Member(String id, String pw, String name, int age, String birth) {
		this.id=id;
		this.pw=pw;
		this.name=name;
		this.age=age;
		this.birth=birth;
	}

	public void showInfo() {
		System.out.println(" ‖ 아이디\t: "+id);
		System.out.println(" ‖  이름\t: "+name+"님");
		System.out.println(" ‖  나이\t: "+age+"살");
		System.out.println(" ‖  생일\t: "+birth);
	}
	@Override
	public String toString() {
		String str=(" ‖ 아이디\t: "+id+"\n ‖  이름\t: "+name+"님"
				+ "\n ‖  나이\t: "+age+"살"+"\n ‖  생일\t: "+birth);
		return str;
	}
}
  • 모든 동작은 서비스 클래스에서 할 것이기 때문에 생성자와 출력 메소드만 만들었다.
  • showInfo랑 toString 둘 다 동일하게 회원 정보를 출력하는 것이다.

 

 1-3) 서비스(동작) ㄱ 

더보기
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import common.JdbcUtil;
import been.Member;

// 회원관리 서비스
public class MemberService {
	Connection con;
	PreparedStatement pstmt;
	ResultSet rs;
	public Member login(String id, String pw) {
		con=JdbcUtil.getConnection();
		String sql = "select*from member where id=? and pw=?";
		try {
			pstmt=con.prepareStatement(sql);
			pstmt.setString(1, id);
			pstmt.setString(2, pw);
			rs = pstmt.executeQuery();
			if(rs.next()) {
				System.out.println(" > "+id+"님 로그인 성공");
				Member m = new Member(id, pw, rs.getString("name"),
						rs.getInt("age"), rs.getString("birth"));
				return m;
			}
		} catch (SQLException e) {
		} finally {
			JdbcUtil.dbClose(rs, pstmt, con);
		}
		return null;
	}
}
  • 입력받은 매개변수를 db에서 찾고, db에 있다면 해당 정보를 가져와서 Member 변수 m에 저장하고 m을 return한다.
  • id, pw 값도 db 값과 동일하니 Member m에 입력할 때 매개변수 값으로 해도 되지만 db 값이 진짜 값이니 id, pw 또한 db에서 가져오는 것도 나쁘지 않다. (나는 코드가 길어지니 줄였다.)
  • 정보 찾기와 입력이 끝났다면 finally를 통해 db를 닫아준다.

 

 

2. 수업일지 29일차 1-3 문제 변형2

로그인할때 틀리면 계속 입력을 받아서 로그인에 성공하면 멈추도록 하기(Member 객체로 반환받기)
위와 동일하지만 Member가 아니라 ArrayList<Member>로 반환받기
admin(관리자) 계정일 경우에는 모든 멤버 정보를 출력하고,
admin(관리자) 계정이 아닐 경우에는 본인의 정보만 출력
  • Member 클래스는 위의 1-2와 동일하게 사용한다.

 2-1) 메인 ㄱ 

더보기
import java.util.ArrayList;
import java.util.Scanner;
import been.Member;
import service.MemberService;

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		// 회원서비스 비지니스로직(업무코드)
		MemberService mSer = new MemberService();
		
		while(true) {
			System.out.print(" 아이디 입력> ");
			String id = sc.next();
			System.out.print(" 비밀번호 입력> ");
			String pw = sc.next();
			ArrayList<Member> mList = mSer.login(id, pw);
			if(mList != null) {
				if(mList.size() == 1) {
					System.out.println(" > "+id+"님의 회원정보");
					System.out.println(" >----------+");
					System.out.println(mList.get(0));
					System.out.println(" >----------+");
				}else {
					System.out.println(" > 회원 정보 출력");
					mSer.showMemberList();
				}
				break;
			}else {
				System.out.println(" > id 또는 pw가 틀렸습니다.\n");
			}
		}
		System.out.println(" > 프로그램 종료");
	}
}
  • 위의 1-1과 비슷하지만 Member가 아닌 ArrayList로 변경했다.
  • 그리고 관리자 계정과 아닌 계정을 구분하여 정보를 출력해야 하기 때문에 if문을 사용했다.
  • 첫번째로 mList가 null인지 아닌지 구분하여 로그인이 되었는지 아닌지 확인한다.
  • 두번째로 mList가 null이 아닐 경우, mList의 길이가 1인지 그 이상인지 확인하여 로그인한 계정이 관리자 계정인지 아닌지 구분한다. 관리자 계정이 아닐 경우에는 로그인한 계정의 회원 정보를 출력하고, 관리자 계정인 경우에는 관리자 계정을 제외한 Member 회원 정보를 전부 출력한다.

 

 2-2) 서비스(동작) ㄱ 

더보기
// 전체 코드 
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

import common.JdbcUtil;
import been.Member;

// 회원관리 서비스
public class MemberService {
	Connection con;
	PreparedStatement pstmt;
	ResultSet rs;
	public ArrayList<Member> login(String id, String pw) {
		ArrayList<Member> mList = null;
		con=JdbcUtil.getConnection();
		String sql = "select*from member where id=? and pw=?";
		try {
			pstmt=con.prepareStatement(sql);
			pstmt.setString(1, id);
			pstmt.setString(2, pw);
			rs = pstmt.executeQuery();
			if(rs.next()) {
				mList = new ArrayList<Member>();
				if(id.equals("ADMIN") || id.equals("admin")) {
					System.out.println(" > 관리자 로그인 성공");
					sql = "select*from member where id!=?";
					pstmt=con.prepareStatement(sql);
					pstmt.setString(1, id);
					rs = pstmt.executeQuery();
					while(rs.next()) {
						Member m = new Member(rs.getString("id"),
							rs.getString("pw"), rs.getString("name"),
							rs.getInt("age"), rs.getString("birth"));
						mList.add(m);
					}
				}else {
					System.out.println(" > "+id+"님 로그인 성공");
					Member m = new Member(id, pw, rs.getString("name"),
							rs.getInt("age"), rs.getString("birth"));
					mList.add(m);
				}
			}
		} catch (SQLException e) {
		} finally {
			JdbcUtil.dbClose(rs, pstmt, con);
		}
		return mList;
	}

	public void showMemberList() {
		con=JdbcUtil.getConnection();
		String sql = "select*from member where id!=?";
		try {
			pstmt=con.prepareStatement(sql);
			pstmt.setString(1, "admin");
			rs = pstmt.executeQuery();
			System.out.println(" >------------------------+");
			System.out.println("ID\tNAME\tBIRTH");
			while(rs.next()) {
				System.out.println(" >--------------+");
				System.out.println(rs.getString("ID")+"\t"+rs.getString("NAME")+
				"\t"+rs.getString("BIRTH"));
			}
			System.out.println(" >------------------------+");
		} catch (SQLException e) {
			System.out.println(" > 정보 불러오기 실패");
			e.printStackTrace();
		} finally {
			JdbcUtil.dbClose(rs, pstmt, con);
		}
	}
}

 

// login 메소드
public ArrayList<Member> login(String id, String pw) {
	ArrayList<Member> mList = null;
	con=JdbcUtil.getConnection();
	String sql = "select*from member where id=? and pw=?";
	try {
		pstmt=con.prepareStatement(sql);
		pstmt.setString(1, id);
		pstmt.setString(2, pw);
		rs = pstmt.executeQuery();
		if(rs.next()) {
			mList = new ArrayList<Member>();
			if(id.equals("ADMIN") || id.equals("admin")) {
				System.out.println(" > 관리자 로그인 성공");
				sql = "select*from member where id!=?";
				pstmt=con.prepareStatement(sql);
				pstmt.setString(1, id);
				rs = pstmt.executeQuery();
				while(rs.next()) {
					Member m = new Member(rs.getString("id"),
						rs.getString("pw"), rs.getString("name"),
						rs.getInt("age"), rs.getString("birth"));
					mList.add(m);
				}
			}else {
				System.out.println(" > "+id+"님 로그인 성공");
				Member m = new Member(id, pw, rs.getString("name"),
						rs.getInt("age"), rs.getString("birth"));
				mList.add(m);
			}
		}
	} catch (SQLException e) {
	} finally {
		JdbcUtil.dbClose(rs, pstmt, con);
	}
	return mList;
}
  • retrun을 한 번만 하기 위해 메소드를 시작할 때 ArrayList<Member> mList를 생성해 null값을 넣어둔다. (null 값을 넣으면 새로 값을 집어넣지 않는 이상 mList를 반환해도 null 값을 반환한 것이 된다.)
  • 매개변수로 받아온 id와 pw가 db에서 확인이 되었다면 id가 admin(관리자)인지 확인하고 맞을 경우, 다시 db에 검색을 해서 id가 admin인 계정을 제외한 계정을 검색해서 m에 저장 후 mList에 저장한다.
  • id가 admin(관리자)가 아닌 경우, 검색된 계정을 m에 저장 후 mList에 저장한다.
  • 마지막에 mList를 반환한다.

 

// showMemberList 메소드
public void showMemberList() {
	con=JdbcUtil.getConnection();
	String sql = "select*from member where id!=?";
	try {
		pstmt=con.prepareStatement(sql);
		pstmt.setString(1, "admin");
		rs = pstmt.executeQuery();
		System.out.println(" >------------------------+");
		System.out.println("ID\tNAME\tBIRTH");
		while(rs.next()) {
			System.out.println(" >--------------+");
			System.out.println(rs.getString("ID")+"\t"+rs.getString("NAME")+
			"\t"+rs.getString("BIRTH"));
		}
		System.out.println(" >------------------------+");
	} catch (SQLException e) {
		System.out.println(" > 정보 불러오기 실패");
		e.printStackTrace();
	} finally {
		JdbcUtil.dbClose(rs, pstmt, con);
	}
}
  • admin(관리자)만 제외하고 출력했다.

 

 

3. Transaction (TX)

 3-1) MySQL ㄱ 

더보기
-- 주문 결제 TX
create table PURCHASE(
PC_NO int auto_increment primary key,				-- 주문번호
PC_MID varchar(10) not null,					-- 주문자 ID
PC_PID varchar(10) not null					-- 상품 ID
);

create table PAY(
	PY_NO int auto_increment primary key,			-- 결제번호
	PY_COST int not null,					-- 결제금액
	PY_PCNO int not null references PURCHASE(PC_NO)		-- 주문번호
);

 

 3-2) TxMain ㄱ 

더보기
import service.ShoppingService;

public class TxMain {
	// 쇼핑 서비스
	public static void main(String[] args) {
		ShoppingService ss = new ShoppingService();
		
		boolean flag = ss.order();
		if(flag) {
			System.out.println(" > 주문 완료");
		}else {
			System.out.println(" > 주문 실패");
		}
	}
}

 

 3-3) JdbcUtil (자주 쓰는 메소드 클래스) ㄱ 

더보기
  • 기본적으로 같지만 수동적으로 commit 하기 위해 getConnection 메소드에서 auto commit만 false로 바꿨다.
public static Connection getConnection() {
	try {
		Connection con = DriverManager.getConnection
        					("jdbc:mysql://localhost:3306/mydb", "icia", "1234");
		con.setAutoCommit(false);	// auto commit 해제. 수동으로 commit 해야함
//		con.setAutoCommit(true); // < 기본 값
		return con;
	} catch (SQLException e) {
		e.printStackTrace();
	}
	return null;
}

 

 3-4) 서비스(동작) ㄱ 

더보기
// 전체 코드
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import common.JdbcUtil;

public class ShoppingService {
	Connection con;
	PreparedStatement pstmt;
	ResultSet rs;
	
	public boolean order() {
		con=JdbcUtil.getConnection();
		String sql="insert into purchase(pc_mid, pc_pid) values(?, ?)";
		try {
			pstmt = con.prepareStatement(sql);	// sql 파싱(컴파일)
			pstmt.setString(1, "B");
			pstmt.setString(2, "컴퓨터");
			int result = pstmt.executeUpdate();	// sql 실행
			if(result>0) {
				System.out.println(" > 상품 주문 성공");
				sql = "insert into pay(py_cost, py_pcno) values(2000000, 2)";
				pstmt = con.prepareStatement(sql);
				result = pstmt.executeUpdate();
				if(result>0) {
					System.out.println(" > 결제 성공");
//					con.commit();
					JdbcUtil.txCommit(con);
					return true;
				}else {
					System.out.println(" > 결제 실패");
//					con.rollback();
					JdbcUtil.txRollback(con);
				}
			}else {
				System.out.println(" > 상품 주문 실패, 결제TX 실패");
			}
		} catch (SQLException e) {
			System.out.println("order 예외");
			e.printStackTrace();
		}
		return false;
	}
}
  • int result에 pstmt.executeUpdate()를 담는다. (문장을 전달해서 값을 받아오는 것에 성공하면 1, 실패하면 0)
  • result 값이 1 이상이라면 다시 db에 문장을 전달하고 값을 받아와서 result에 받는다.
  • result 값이 두 번 모두 1 이상이라면 JdbcUtil 클래스에 만들어둔 txCommit 메소드를 사용하여 db에서 commit해준다. (con.commit: 자바에서 만들어둔 메소드)
  • result 값이 1 이상이었다가 두번째에서 아니게 됐다면 db에서 rollback해준다. (con.rollback: 자바에서 만들어둔 메소드)

 


 

전체 피드백

  • 주말에 수업일지 읽으면서 복습하는 것이 아니라 예제 비슷하게 내고 코드를 만들어보면서 코드(영어!)와 친해져야 할 것 같다.
  • 나는 db보다 자바가 더 잘맞는 것 같다. 자바로 돌아오니까 재밌다..

 


728x90
728x90

 

수업내용 정리 (Java)

 

1. Jdbc

 

  • MySQL ㄱ 
더보기
-- test table
Create table member(
	ID varchar(20) PRIMARY KEY,
	PW varchar(20) NOT NULL,
	NAME varchar(20) NOT NULL,
	AGE tinyint unsigned NOT NULL,
	BIRTH date default (current_DATE)
);
select*FROM MEMBER;
-- test data
INSERT INTO MEMBER VALUES('A','1111','에이', 20, DEFAULT);
INSERT INTO MEMBER VALUES('B','2222','비비', 21, '2023-10-31');
INSERT INTO MEMBER VALUES('C','3333','씨씨', 22, DEFAULT);
INSERT INTO MEMBER VALUES('D','4444','디디', 30, DEFAULT);
INSERT INTO MEMBER VALUES('E','5555','이이', 32, DEFAULT);

 

 

더보기
Connection con;
PreparedStatement pstmt;
ResultSet rs;
  • Connection con: db 접속을 위한 객체 생성
  • PreparedStatement pstmt: sql 문장과 db 전달
  • ResultSet rs: select 결과 저장

 

 

public static void main(String[] args) {
	JdbcConnectionTest conTest=new JdbcConnectionTest();
	conTest.connect();
       
	// select, insert, ...
	conTest.select();
	conTest.select(30, "에이");
	conTest.insert("L", "101010", "엘", 34, "2010-10-10");
	
	conTest.dbClose();
}

 

// conTest.connect();
public void connect() {	/* java and db 연결 */
	try {
		con=DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "icia", "1234");
		System.out.println("db 접속 성공");
	} catch (SQLException e) {
		System.out.println("db 접속 실패");
		e.printStackTrace();
	}
}
  • db 접속을 위해 만들어둔 con 객체에 getConnection 메소드를 통해 db 접속
  • getConnection("db 주소", "id", "pw") 구조로 적는다.
  • localhost: ip적는곳 / 현재 컴퓨터에 있는 db를 사용한다면 localhost를 통해 접근이 가능하다.
  • db 접속에 실패할 수도 있으므로 try-catch문을 이용하여 작성해야 한다.

 

// conTest.dbClose();
private void dbClose() {	/* java and db 연결 종료 */
	try {
		con.close();
		System.out.println("db 종료 성공");
	} catch (SQLException e) {
		System.out.println("db 종료 실패");
		e.printStackTrace();
	}
}
  • con 객체에 close 메소드를 통해 db 연결 해제
  • 연결 해제에 실패할 때를 대비하여 try-catch문을 이용하여 작성한다.

 

// conTest.select();
private void select() {
	String sql="select*from member";
	try {
		pstmt=con.prepareStatement(sql);
		rs=pstmt.executeQuery(); // executeQuery는 select만
		while(rs.next()) {
			System.out.println("아이디: "+rs.getString("ID")); // ID 칼럼에 있는 값을 반환
			System.out.println("비밀번호: "+rs.getString("PW"));
			System.out.println("이름: "+rs.getString("NAME"));
			System.out.println("나이: "+rs.getInt("AGE"));
			System.out.println("생일: "+rs.getDate("BIRTH"));
			System.out.println(" -----:");
		}
	} catch (SQLException e) {
		System.out.println("select 예외 발생");
		e.printStackTrace();
	}
	System.out.println("select 완료");
}
  • String sql="~"; : sql에서 실행할 문장을 적는다.
  • pstmt=con.prepareStatement(sql); : sql 문장을 db에 전달 파싱(분석) / 컴파일과 비슷하다고 생각해도 된다.
  • rs=pstmt.executeQuery(); : db에서 select문을 실행한다.
  • while문: 조건에 rs.next()를 넣어 rs의 다음 값이 있는지 확인하고  다음 값이 없으면 while문을 종료한다. sysout을 통해 rs에 담긴 값을 받아와 출력한다.
  • 에러가 날 수 있으므로 try-catch문을 이용하여 작성한다.

 

// conTest.select(30, "에이");
private void select(int age, String name) {
	String sql="select*from member where AGE>=? OR NAME=?";
	try {
		pstmt=con.prepareStatement(sql);
		pstmt.setInt(1, age);
		pstmt.setString(2, name);
		rs=pstmt.executeQuery(); // executeQuery는 select만
		while(rs.next()) {
			System.out.println("아이디: "+rs.getString("ID")); // ID 칼럼에 있는 값을 반환
			System.out.println("비밀번호: "+rs.getString("PW"));
			System.out.println("이름: "+rs.getString("NAME"));
			System.out.println("나이: "+rs.getInt("AGE"));
			System.out.println("생일: "+rs.getDate("BIRTH"));
			System.out.println(" -----:");
		}
	} catch (SQLException e) {
		System.out.println("select 예외 발생");
		e.printStackTrace();
	}
	System.out.println("select 완료");
}
  • 전체적인 구조는 위와 같지만, 조건이 있기 때문에 조금 다르다.
  • sql문을 작성할 때 매개변수를 바로 작성할 수 있으나 붙여주기 까다로우니 물음표(?)로 대체해주고 밑에서 pstmt.set~(n,m)을 이용하여 작성해준다.
  • pstmt.set~(n,m): ~은 타입을 적고, n은 물음표(?)의 위치(왼쪽부터 순서대로 1~), m은 물음표(?)에 넣고 싶은 매개변수를 적는다.

 

// conTest.insert("L", "101010", "엘", 34, "2010-10-10");
private void insert(String id, String pw, String name, int age, String birth) {
	String sql="insert into member(id, pw, name, age, birth) "
			+ "values(?, ?, ?, ?, ?)";
	try {
		pstmt = con.prepareStatement(sql);
		pstmt.setString(1, id);
		pstmt.setString(2, pw);
		pstmt.setString(3, name);
		pstmt.setInt(4, age);
		pstmt.setString(5, birth);
		pstmt.executeUpdate();	// insert, updqte, delete 실행
	} catch (SQLException e) {
		System.out.println("insert 예외 발생");
		e.printStackTrace();
	}
}
  • 매개변수로 받아온 값들을 물음표(?) 위치에 맞게 집어넣고, executeUpdqte(insert, update, delete 실행) 메소드를 통해 실행한다.
  • 마찬가지로 오류가 날 수 있으니 try-catch문을 이용한다.

 

 

 

// 문제1 회원 G 삭제
conTest.delete("쥐");
// 문제2 회원 A의 나이를 50살로 변경
conTest.update("A", 50);
private void update(String id, int age) {
	String sql="update member set age=? where id=?";
	try {
		pstmt = con.prepareStatement(sql);
		pstmt.setInt(1, age);
		pstmt.setString(2, id);
		pstmt.executeUpdate();	// insert, updqte, delete 실행
	} catch (SQLException e) {
		System.out.println("insert 예외 발생");
		e.printStackTrace();
	}
}

private void delete(String id) {
	String sql="delete from member where id=?";
	try {
		pstmt = con.prepareStatement(sql);
		pstmt.setString(1, id);
		pstmt.executeUpdate();	// insert, updqte, delete 실행
	} catch (SQLException e) {
		System.out.println("insert 예외 발생");
		e.printStackTrace();
	}
}
  • delete와 updqte 모두 insert를 할 때처럼 비슷하게 매개변수를 받고 물음표 위치에 따라 맞는 매개변수를 입력한다.
  • executeUpdate를 사용하여 실행한다.
  • 마찬가지로 오류가 날 수 있으므로 try-catch문을 이용한다.

 

 

 1-2) 자주 쓸 메소드 (클래스로 빼두기) ㄱ 

더보기
package common;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class JdbcUtil {
	static {
		try {
			Class.forName("com.mysql.cj.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	public static Connection getConnection() {
		try {
			Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "icia", "1234");
			return con;
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public static void dbClose(ResultSet rs, PreparedStatement pstmt, Connection con) {
		try {
			if(rs!=null) rs.close();
			if(pstmt!=null) pstmt.close();
			if(con!=null) con.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
    
	public static void txCommit(Connection con) {
		try {
			con.commit();
		} catch (SQLException e) {
			System.out.println("commit fail");
			e.printStackTrace();
		}
	}
	public static void txRollback(Connection con) {
		try {
			con.rollback();
		} catch (SQLException e) {
			System.out.println("rollback fail");
			e.printStackTrace();
		}
	}
}

 

 

2. 문제

로그인할때 틀리면 계속 입력을 받아서 로그인에 성공하면 멈추도록 하기(boolean으로 반환받기)
회원 전체 출력하기

 2-1) 메인 ㄱ 

더보기
public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		// 회원서비스 비지니스로직(업무코드)
		MemberService mSer = new MemberService();
		
		while(true) {
			System.out.print(" 아이디 입력> ");
			String id = sc.next();
			System.out.print(" 비밀번호 입력> ");
			String pw = sc.next();
			boolean result = mSer.login(id, pw);
			if(result) {
				break;
			}else {
				System.out.println(" > id 또는 pw가 틀렸습니다.\n");
			}
		}
		mSer.showMemberList(); // 회원 전체 출력
		System.out.println(" > 프로그램 종료");
	}
}

 

 2-2) 서비스 ㄱ 

더보기
// 회원관리 서비스
public class MemberService {
	Connection con;
	PreparedStatement pstmt;
	ResultSet rs;

	public boolean login(String id, String pw) {
		con=JdbcUtil.getConnection();
		String sql = "select*from member where id=? and pw=?";
		try {
			pstmt=con.prepareStatement(sql);
			pstmt.setString(1, id);
			pstmt.setString(2, pw);
			rs = pstmt.executeQuery();
			if(rs.next()) {
				System.out.println(" > "+id+"님 로그인 성공");
				return true;
			}
		} catch (SQLException e) {
		} finally {
			JdbcUtil.dbClose(rs, pstmt, con);
		}
		return false;
	}

	public void showMemberList() {
		con=JdbcUtil.getConnection();
		String sql = "select*from member";
		try {
			pstmt=con.prepareStatement(sql);
			rs = pstmt.executeQuery();
			System.out.println("ID\tNAME");
			System.out.println(" >-----+");
			while(rs.next()) {
				System.out.println(rs.getString("ID")+"\t"+rs.getString("NAME"));
				System.out.println(" >-----+");
			}
		} catch (SQLException e) {
			System.out.println(" > 정보 불러오기 실패");
			e.printStackTrace();
		} finally {
			JdbcUtil.dbClose(rs, pstmt, con);
		}
	}
}
  • try로 들어가든 catch로 들어가든 무조건 finally문을 실행하기 때문에 db 연결을 해제하는 메소드는 finally문에 넣었다.

 

로그인
회원 전체 출력

 

 


 

질문한 내용이나 어려웠던 점 메모

  • 영어가 너무 익숙하지 않다...

 


 

 + 빨리 프론트엔드도 배워보고싶다..!

728x90
728x90

 

수업내용 정리 (MySQL)

 

1. view

  • 논리적인 테이블
  • 사용하는 목적: 검색 단순화, 보안 용이
  • or replace를 추가하면 drop -> create를 하지 않고 업데이트하여 사용할 수 있다.
create or replace view emp_view as select empno, deptno, job, ename from emp
where job<>'clerk' order by ename;
select*from emp_view;

select로 출력한 view

 

create or replace view emp_view as select empno, deptno, job, ename
from emp order by deptno, empno;

select*from emp_view where deptno=10 or deptno=20;
  • 만들어두고 select로 출력할 때 조건을 줄 수도 있다!

 


 

전체 피드백

  • 오늘은 eXERD라는 프로그램을 통해 테이블 짜는 것을 해보고 그러느라 MySQL에서 배운 것은 view밖에 없었다.

 


728x90
728x90

 

수업내용 정리 (MySQL)

 

1. 제약 조건

 1-1) 제약 조건 ㄱ 

더보기
제약 설명
AUTO_INCREMENT 새 행 생성 시마다 자동으로 1씩 증가
PRIMARY KEY (PK, 기본키) 중복 입력 불가(UQ), NULL(빈 값) 불가 / 테이블에 무조건 하나
FOREIGN KEY (FK, 외래키) 참조되는 부모 테이블의 PK 또는 UQ 칼럼 값 중의 하나를 가진다.
UNIQUE (UQ) 중복 입력 불가 / null 값은 연산에서 제외
NOT NULL NULL(빈 값) 입력 불가 / 칼럼단에서만 설정 가능
UNSIGNED (숫자일 시) 양수만 가능
DEFAULT 값 입력이 없을 시 기본 값  / 칼럼단에서만 설정 가능
  • 외래키(FK) 설정을 안 하면 자동으로 랜덤한 칼럼에 설정된다.
  • DESC로 테이블 구조를 확인할 때 외래키는 MUL이라고 적혀있다.
  • 제약 조건 우선 순위: PRIMARY KEY > FOREIGN KEY > UNIQUE

 

  • FOREIGN KEY는 3번에서 다룬다.

 

 1-2) 제약 조건 삭제 / 추가

더보기
-- 제약조건 삭제
alter table member drop constraint PK_M_ID;	-- oracle 기준
alter table member drop primary key;	-- auto_increment 시 삭제 불가
alter table member drop constraint UQ_M_T;
  • PK에 Auto_increment를 설정했을 시, 삭제가 불가능하다.

 

-- 제약조건 설정(추가)
alter table member add constraint PK_M_ID primary key (M_ID);	-- oracle 기준
alter table member add primary key(M_ID);
alter table member add constraint UQ_M_TEL unique(M_tel);
  • 제약 조건을 줄 때 이름을 설정해야 나중에 삭제해야 할 때 용이하다.

 

-- not null/ null 수정
-- alter table member modify M_TEL null;	-- oracle 기준
alter table member modify M_TEL char(12) null;	-- 타입도 변경 가능
alter table member modify M_TEL char(11) not null;

-- 기본값 변환
alter table member modify M_age int default 1;
alter table member modify M_age tinyint unsigned default 1;
  • 타입을 꼭 적어야 하고, 다른 타입으로 적을 시 타입이 변경된다. (Oracle은 안 적어도 된다)

 

 

2. 

 2-1) 테이블 생성 ㄱ 

더보기
drop table if exists member;
create table member(
	M_ID varchar(20),
	M_name varchar(20) not null,
	M_age tinyint unsigned default 0 not null,
	M_tel char(11) not null,
	M_email varchar(40),
	-- - 테이블단 제약 조건
	primary key PK_M_ID (M_ID),
	constraint unique UQ_M_T (M_tel), unique UQ_M_E (M_email)
);
  • 칼럼단에서 제약조건을 설정할 수 있지만 테이블단에서 제약 조건을 주는 것이 보기에 좋다.
  • not null, default는 칼럼단에서만 가능하다. (따로 생성/삭제 가능하지만 테이블 생성할 때는 테이블단에서 불가능)
  • M_tel에 타입을 char로 했기 때문에 값을 '010111122' 로 저장하면 남은 공간은 공백으로 저장된다. select 때 MySQL은 알아서 trim으로 공백을 빼고 가져온다. oracle은 아님!
  • MySQL은 PK명이 붙지 않고, ORACLE에서만 붙는다. PK명을 설정한 상태로 테이블을 생성해도 PK명이 저장되지 않는다.
  • constraint <- 안 써도 정상적으로 작동되긴 한다.

 

 2-2) 데이터 삽입 ㄱ 

더보기
insert into member(M_ID, M_name, M_tel, M_age) values('A', '에이', '0101111', default);
select M_ID, length(M_ID), M_name, length(M_name), M_tel, length(M_tel) from member;
select M_ID, char_length(M_ID), M_name, char_length(M_name), M_tel, length(M_tel) from member;
  • 글자 크기와 글자 수를 확인할 수 있다.

 

insert into member(M_id, m_name, m_tel, m_age) values('B', '비', '0102222', 10);
insert into member(M_id, m_name, m_tel, m_age)
	values('C', '씨', '01033332323', 20),
		('D', '디', '01044442323', 30),
		('E', '이', '01055552323', 40);
  • 한번에 데이터를 삽입 할 수도 있다.

 

 

3. 제약 조건:  FOREIGN KEY

더보기
  • 부모 테이블 -------< 관계(R) >------- 자식 테이블

 

drop table if exists board;
create table board(
	B_NO bigint auto_increment primary key,
	B_TITLE varchar(100) not null,
	B_CONTENTS varchar(10000) not null,
	B_DATE datetime not null default now(),
	B_MID varchar(20) not null,
-- ------ 외래키 제약 설정
	constraint FK_B_MID foreign key (B_MID) references member(M_ID)
);
  • FK(외래키): 부모 테이블과 자식 테이블을 연결하는 데에 사용되는 키
  • 부모 테이블의 기본키/고유키를 외래키로 지정할 수 있다.
  • 칼럼단에서도 제약 조건을 줄 수 있지만 테이블단에서 주는 것이 보기에 좋다.
  • 위 코드처럼 외래키만 설정하고 설정 옵션을 붙이지 않으면 부모 테이블에서 수정/삭제할 수 없게 된다.

 

-- 자식(board) 데이터 추가
insert into board values(null, '제목1', '내용1', default, 'xxx');
insert into board values(null, '제목1', '내용1', default, 'A'),
			(null, '제목2', '내용2', default, 'A'),
			(null, '제목1', '내용1', default, 'B'),
			(null, '제목2', '내용2', default, 'B'),
			(null, '제목1', '내용1', default, 'C'),
			(null, '제목2', '내용2', default, 'C');
  • 맨 위의 코드는 참조되는 member(부모 테이블)에 없는 ID라서 에러가 뜨고 저장되지 않는다.
  • 두번 코드처럼 여러개를 동시에 추가할 수 있다.

 

-- 'A' 회원 탈퇴
delete from member where M_ID='A';	-- 외래키 때문에 안 됨
delete from member where M_ID='D';	-- 자식 테이블에서 글이 없기 때문에 성공
delete from board where B_MID='A';	-- 자식 레코드(데이터) 삭제
delete from member where M_ID='A';	-- 자식 레코드(데이터)를 삭제했기 때문에 삭제 성공

-- member(부모) 테이블 삭제
drop table member;	-- 자식 테이블이 있기 때문에 안 됨
  • MEMBER 테이블을 BOARD 테이블에 외래키로 넣어놨기 때문에 BOARD 테이블에서 데이터를 사용했는데 그냥 삭제하려고 하면 삭제되지 않는다.
  • 자식 테이블에서 사용하지 않은 데이터는 바로 삭제할 수 있다.
  • 자식 테이블에서 연관된 데이터 삭제 시 부모 테이블에서 데이터를 삭제할 수 있다.
  • 테이블 또한 마찬가지로 자식 테이블에서 참조하고있기 때문에 삭제할 수 없다.

 

 

drop table board;
drop table member;
  • 밑에서 MEMBER 테이블을 사용해야 하니 둘 다 삭제했다.

 

 3-1) 외래키 설정 옵션 ㄱ 

더보기
  • 외래키 설정 옵션
    • on update: 수정 시 / on delete: 삭제 시
    • restrict: 참조하는 테이블(자식 테이블)에 참조되는 테이블(부모 테이블)의 데이터가 남아 있으면 참조되는 테이블(부모)에서 수정/삭제를 할 수 없다.
    • cascade: 참조되는 테이블(부모)에서 데이터 수정/삭제를 하면 참조하는 테이블(자식)에서도 수정/삭제가 된다.
    • no action: 참조되는 테이블(부모)에서 데이터 수정/삭제를 해도 참조하는 테이블(자식)의 데이터는 변경되지 않는다.
    • set default: 참조되는 테이블(부모)에서 데이터 수정/삭제를 하면 참조하는 테이블(자식)의 데이터는 default값으로 설정된다.
    • set null: 참조되는 테이블(부모)에서 데이터 수정/삭제를 하면 참조하는 테이블(자식)의 데이터는 null이 된다.

 

 

4. 문제? (외래키를 이용해서 테이블 만들기)

더보기
  • 조건
    • 모든 칼럼은 NULL 값을 포함하지 않는다.
    • PURCHASE(구매) 테이블의 PRIMARY KEY는 조합키(슈퍼키)로 한다.
MEMBER (고객)
아이디 비밀번호 이름 전화번호 이메일
PRIMARY KEY       UNIQUE
PRODUCT (제품)
제품 번호 제품명 가격 재고 제품 설명
PRIMARY KEY
AUTO_INCREMENT
       
PURCHASE (구매)
주문 번호 구매 고객 구매 제품 번호 구매 수량 구매 시간
AUTO_INCREMENT FOREIGN KEY FOREIGN KEY    

 

 

create table MEMBER(
	M_ID varchar(20),
	M_PW varchar(20) not null,
	M_NAME varchar(20) not null,
	M_TEL varchar(13) not null,
	M_EMAIL varchar(30) not null,
	constraint primary key PK_M_ID (M_ID),
	constraint unique UQ_M_E (M_EMAIL)
);
  • NULL 값을 허용하지 않는다고 했으니 PRIMARY KEY를 넣을 M_ID를 제외한 칼럼에 NOT NULL을 입력했다.
  • 테이블 단에서 PK를 설정할 때 MySQL은 이름을 정해줄 수 없지만 Oracle에서는 정할 수 있으므로 연습하는 겸 이름도 적었다.

 

create table PRODUCT(
	P_NO int auto_increment,
	P_NAME varchar(30) not null,
	P_PRICE int unsigned not null default 10000,
	P_Inven int unsigned not null default 0,
	P_Intro text not null,
	constraint primary key PK_P_NO (P_NO) 
);
  • DEFAULT 값으로 P_PRICE(가격)에는 10,000, P_INVEN(재고)에는 0을 입력했다.

 

create table PURCHASE(
	PR_NO int auto_increment,
	PR_MID varchar(20),
	PR_PNO int,
	PR_Quti tinyint not null,
	PR_DATE datetime default now(),
	constraint primary key PK_PR (PR_NO, PR_MID, PR_PNO, PR_DATE),	-- 조합키(슈퍼키)
	constraint foreign key FK_PR_MID (PR_MID) references MEMBER (M_ID)
							on delete no action on update cascade,
	constraint foreign key FK_PR_PNO (PR_PNO) references PRODUCT (P_NO)
							on delete no action on update cascade
);
  • FK로 데이터를 가져올 칼럼에는 해당 데이터 칼럼의 타입을 그대로 적는다. (변경할 수는 있지만 그대로인 경우가 헷갈리지 않고 오류날 일 없이 편하다.)
  • PRIMARY KEY에 여러가지 칼럼을 설정하면 조합(슈퍼)키가 된다.
  • FOREIGN KEY를 각 각 PR_MID, PR_PNO에 설정해준다. PR_MID는 MEMBER 테이블에서 M_ID를, PR_PNO는 PRODUCT 테이블에서 P_NO를 참조한다.
  • FK 설정 옵션 중, ON DELETE에는 NO ACTION으로 부모 테이블에서 데이터를 삭제한다고 해도 해당 데이터는 삭제되지 않도록 했다.
  • ON UPDATE는 CASCADE로 부모 테이블에서 데이터를 변경하면 해당 데이터도 변경되도록 했다.

 

insert into member(M_ID, M_PW, M_NAME, M_TEL, M_EMAIL)
			values ('A', 'AAA', '에이', '010-1111', 'AA@AAAAA.AAA');
            
insert into member values('B', 'BBB', '비비', '010-2222', 'BB@BBBB.BBB'),
			('C', 'CCC', '씨씨', '010-3333', 'CC@CCCCC.CCC'),
			('D', 'DDD', '디디', '010-4444', 'DD@DDDDD.DDD');
  • 위 코드처럼 칼럼을 적고 추가하는 것이 좋다. (많은 칼럼이 있을 경우 순서를 헷갈릴 수 있기 때문에)

 

insert into product
	values (null, 'TV', default, 20, 'TVTVTVTVTVTVTVTVTVTVTVTVTTVTVTVVTTVTVTVTVTVTVTVTV'),
		(null, '냉장고', 20000, 15, 'Coolllllllllllllllllllllllllllllllllllllllllllllllll'),
		(null, '오븐', 30000, 10, 'Hottttttttttttttttttttttttttttttttttttttttttttttttttt'),
		(null, 'PC', 40000, 5, 'PCPCPPCPPCPCPCPCPCPCPPCPCPCPCPPCPCPCPCPPCPCPCPPCPCPCPCPPC');
insert into purchase values (null, 'A', 1, 10, default),
			(null, 'B', 2, 2, default),
			(null, 'B', 3, 4, default),
			(null, 'C', 4, 3, default),
			(null, 'D', 4, 2, default);

 

select PR_NO '구매 번호', PR_MID '구매자', P_NO '구매한 상품 번호', P_NAME '구매한 상품', PR_DATE '구매한 날짜'
from purchase PR join product P on P.P_NO=PR.PR_PNO where P.P_Inven-PR.PR_Quti>=0;

 

update member set M_ID='AA' where M_ID='A';
  • 부모 테이블에서 데이터를 변경해도 자식 테이블에서 문제없이 변경된다.

 


 

 

 - 쌤이 정리해주신 테이블 관련 코드

-- ALTER TABLE - 테이블 변경, COLUMN 생략 가능
-- 테이블명 변경
ALTER TABLE people RENAME TO  friends,
-- 컬럼 자료형 변경
CHANGE COLUMN person_id person_id TINYINT,
-- 컬럼명 변경
CHANGE COLUMN person_name person_nickname VARCHAR(10), 
-- 컬럼 삭제
DROP COLUMN birthday,
-- 컬럼 추가
ADD COLUMN is_married TINYINT AFTER age,
-- 기본키, AUTO_INCREMENT 설정
Change COLUMN m_id m_id int auto_increment PRIMARY KEY,
-- AUTO_INCREAMENT 제거
change COLUMN m_id m_id int,
-- PK 제거
drop primary key;

 


 

전체 피드백

  • 역시 내가 직접 무언가 해봐야 식곤증이 덜 오는 것 같다..

 


728x90
728x90

 

수업내용 정리 (MySQL)

 

1. Join

더보기
select*from dept;	-- 부모 테이블 1개
select*from emp;	-- 자식 테이블 n개(여러개 가능)
select*from salgrade;
  • join: 두 개 이상의 테이블을 행끼리 결합하는 DB의 꽃

 

  • inner(내부) join: 양 쪽(테이블) 모두에 값이 있는 행 반환(not null)
  • 기본이 inner join이기 때문에 'inner' 생략 가능!
  • 모호성(ambiguous)에 주의할 것! 테이블명에 알리어스(as)를 넣어 별칭을 지어주기.
  • 만족하는 모든 행을 결합(join)한다.

 

-- 표준(ANSI) SQL 조인
select * from dept D
join emp E
on D.deptno=E.deptno  -- 조인조건	/ 동일조인
where JOB='CLERK';	-- 일반조건
  • 표준(ANSI) SQL 조인
  • join [join 할 테이블]
  • on [join 할 조건]

 

-- 비표준 SQL 조인
select * from dept D, emp E
where D.deptno=E.deptno;

select * from dept D, emp E
where D.deptno=E.deptno and job='CLERK';
  • join을 적지 않고 join하는 방법
  • from에 테이블을 여러개 적고, join 조건을 where절에 적는다.
  • 밑의 코드는 where절에 join조건과 일반 조건이 함께 들어있다. where [join 조건] and [일반 조건]

 

 

 예제 ㄱ

-- 테이블 2개 조인
select e.ename, e.sal, concat(s.grade, '호봉') grade
from salgrade s
join emp e on e.sal between s.losal and s.hisal;	-- 비동일 조인(>= <=)
-- 테이블 3개 조인
select* from dept d
join emp e on d.deptno=e.deptno
join salgrade s on e.sal between s.losal and s.hisal;
-- 3번 
select e.ename, e.sal, s.grade, s.stdsal from emp e
join salgrade2 s on truncate(e.sal,-3)=truncate(s.stdsal,-3);

 

 

  • 인라인뷰(view): from절에 서브쿼리가 들어간 것
  • 하드디스크가 아닌 메모리 상에서만 존재하는 논리적인 테이블
  • 인라인끼리 혹은 내/외부 조인과도 같이 조인이 가능하다.
-- 10번 부서와 20번 부서 사원 중에서 직급이 같은 사원들의 이름, 부서번호, 직급을 검색 
select e1.job, e1.deptno, e1.ename, e2.deptno, e2.ename
from (select ename, deptno, job from emp where deptno=10) e1
join (select ename, deptno, job from emp where deptno=20) e2
where e1.job=e2.job;

 

 

select e.empno '사원번호', e.ename '사원 명', e.mgr '상사번호', m.ename '상사'
from emp e join emp m on e.mgr=m.empno order by e.empno;	-- 상사가 없는 경우 검색되지 않음
  • self join: 내부 조인. 같은 테이블끼리 join한다.
  • 해당 코드는 상사가 없는 경우엔 출력되지 않는다.

 

select e.empno '사원번호', e.ename '사원 명', e.mgr '상사번호', m.ename '상사'
from emp e left join emp m on e.mgr=m.empno order by e.empno;
  • 잉여 데이터가 있는 경우에도 출력할 수 있는 Left / Right Join
  • Left / Right outer join: 외부 조인. 반대쪽에 데이터가 있든 없든(null), 선택된 방향에 있으면 출력 - 행 수 결정 (Left join: 오른쪽에 잉여데이터 / Right join: 왼쪽에 잉여데이터)
  • 중간에 있는 outer은 생략이 가능하다.
  • 해당 코드는 상사가 없는 경우에도 출력이 된다.

 3번 예제에 쓰인 테이블 ㄱ 

더보기
drop table salgrade2;
create table salgrade2(
	grade int  primary key,	-- 기본 키
	stdsal int
);	-- create end
select*from salgrade2;	-- 확인 
insert into salgrade2(grade, stdsal) values(1, 0);	-- 값 집어넣기 / 0~999 1호봉
insert into salgrade2(grade, stdsal) values(2, 1000);	-- 1000~1999
insert into salgrade2(grade, stdsal) values(3, 2000);	-- 2000~2999
insert into salgrade2(grade, stdsal) values(4, 3000);	
insert into salgrade2(grade, stdsal) values(5, 4000);	
insert into salgrade2(grade, stdsal) values(6, 5000);	-- 5000~5999

 

 문제 ㄱ 

더보기
  • 문제
-- 1) comm을 받는 사원의 부서명, 부서위치, 이름, 커미션(comm) 검색
-- 2) 'dallas'(부서위치)에서 근무하는 사원 부서번호, 부서명, 이름, 직급 검색
-- 3) 'ward'(사원이름)의 부서이름과 이름 검색
-- 4) 사원이름, 급여, 급여등급 검색
-- 5) 부서명, 사원이름, 급여등급 검색
-- 6) 부서별 부서이름, 최소급여, 최대급여, 평균급여 검색
-- 7) 부서 내에서 직급별 부서번호, 부서명, 직급, 평균급여, 인원수 검색

 

 

  • 풀이
-- 1) comm을 받는 사원의 부서명, 부서위치, 이름, 커미션(comm) 검색
select d.dname, d.loc, e.ename, e.comm from dept d
join emp e on d.deptno=e.deptno where ifnull(comm,0)<>0;
  • 부서명, 부서위치, 이름, 커미션은 검색했으나 comm을 받는 사람만 출력하는 것에서 실패하고 시간이 끝났다.
  • 부서명, 부서위치가 한 테이블, 사원이름, 커미션이 한 테이블로 각 두 테이블이 있으니 join을 했다.
  • join 조건은 두 테이블 모두 동일하게 가지고 있는 deptno
  • comm을 받는 사원이 조건이므로 where절에 comm이 null이 아닐 때라는 조건을 준다.
  • ifnull(comm,0)<>0은 comm<>0으로도 변경이 가능하다.

 

-- 2) 'dallas'(부서위치)에서 근무하는 사원 부서번호, 부서명, 이름, 직급 검색
select d.deptno, d.dname, e.ename, e.job from dept d
join emp e on d.deptno=e.deptno where d.loc='dallas';
  • 부서명은 dept 테이블에 있고 / 사원이름, 사원직급은 emp 테이블에 있고 / deptno는 두 테이블 모두에 있으므로 dept 테이블과 emp 테이블을 join해주면서 deptno를 join 조건으로 줬다.
  • 일반 조건으로는 부서위치가 'dallas'인 조건이 있으므로 dept 테이블에 있는 loc(부서위치)가 'dallas'인 것만 이라는 조건을 준다.

 

-- 3) 'ward'(사원이름)의 부서이름과 이름 검색
select d.dname, e.ename from dept d join emp e on d.deptno=e.deptno where e.ename='ward';
  • 부서명은 dept 테이블, 사원 이름은 emp 테이블에 있으므로 두 테이블을 join해주고, 조건은 동일하게 가지고 있는 칼럼인 deptno를 준다.
  • 'ward'의 부서명과 이름을 검색하라고 했으니 emp 테이블에 있는 ename의 값이 'ward'인 것만 이라는 조건을 준다.

 

-- 4) 사원이름, 급여, 급여등급 검색
select e.ename, e.sal, s.grade from emp e join salgrade s on e.sal between s.losal and s.hisal;
  • 사원이름은 emp 테이블, 급여등급은 salgrade 테이블에 있으므로 두 테이블을 join해준다.
  • join 조건으로는 emp 테이블에 있는 sal이 salgrade 테이블에 있는 losal과 hisal의 사이일 경우로 준다.

 

-- 5) 부서명, 사원이름, 급여등급 검색
select d.dname, e.ename, s.grade from dept d
join emp e on d.deptno=e.deptno join salgrade s on e.sal between s.losal and s.hisal;
  • 부서명, 사원이름, 급여등급이 각 다른 테이블에 있기 때문에 각 테이블을 모두 join해준다.
  • join 조건은 dept에 emp를 join할 때는 deptno가 동일할 경우로 주고, salgrade를 join할 때는 emp의 sal이 salgrade의 losal과 hisal의 사이일 경우로 준다.

 

-- 6) 부서별 부서이름, 최소급여, 최대급여, 평균급여 검색
select d.dname '부서명', min(e.sal) '최소급여', max(e.sal) '최대급여', round(avg(e.sal),2) '평균급여'
from dept d join emp e on d.deptno=e.deptno
group by d.deptno order by d.dname;
  • 부서명은 dept 테이블, 나머지는 emp 테이블에서 구하면 되기 때문에 dept 테이블과 emp 테이블을 join해준다.
  • join 조건은 deptno가 동일할 경우로 준다.
  • 최소 급여, 최대 급여, 평균 급여 값은 각 min, max, avg 함수를 사용하여 구한다.

 

-- 7) 부서 내에서 직급별 부서번호, 부서명, 직급, 평균급여, 인원수 검색
select d.deptno '부서번호', d.dname '부서명', e.job '직급',
	round(avg(e.sal),2) '평균급여', count(e.job) '인원수'
from dept d join emp e on d.deptno=e.deptno group by e.deptno;

select round(avg(e.sal)) '평균급여', concat(count(*), '명') '인원 수', d.deptno, d.dname, e.job
from dept d join emp e on d.deptno=e.deptno
group by d.deptno, e.job, d.dname;
  • 위에 코드가 내가 풀다가 실패한 코드이고, 밑에 코드가 선생님이 풀이해주신 코드이다.
  • 내가 코드를 짤 때 그룹으로 묶을 것을 적게 줘서 오류가 났었다.
  • 우선 필요한 테이블인 dept와 emp를 join해주고 조건은 두 테이블 모두에 있는 deptno가 동일할 경우로 준다.
  • 그룹화를 해야 하는데 select에 여러 칼럼을 적었으므로 적은 칼럼을 모두 group by에 적는다. (SQL에선 d.dname은 그룹으로 안 묶어도 실행된다. Oracle에서는 안 됨!)

 

 

-- 문)
-- 본인의 사원 이름, 부서번호를 검색하고,
-- 같은 부서의 동료사원의 사원이름, 부서번호를 검색하시오
-- 이름순으로 오름정렬하시오
-- 실행예
-- 본인 부서번호 동료 부서번호
-- allen 30 blake 30
-- allen 30 james 30
-- ...
-- blake 30 allen 30
select e.ename '본인', e.deptno '부서번호', d.ename '동료', d.deptno '부서번호'
from emp e join emp d on e.deptno=d.deptno where e.ename<>d.ename order by e.ename, d.ename;
  • 같은 테이블(emp) 내의 값이 필요하므로 self join을 해준다.
  • join 조건은 같은 부서의 동료 사원이 필요하므로 deptno로 주고, 본인이 나오면 안 되기 때문에 일반 조건에 첫번째 ename과 두번째 ename이 같을 경우를 제외해준다.
  • 이름순으로 오름정렬하라고 했기 때문에 order by에 첫번째와 두번째 ename을 모두 적어준다.

 

 

2. 자료형

더보기
  • 전부 외우지 않아도 됨! 몇가지만 좀 알고 있기!
  • 선생님이 주신 PPT에서 긁어왔다.

 

  • 숫자 자료형
자료형 바이트 SIGNED UNSIGNED
TINYINT 1 -128 ~ 127 0 ~ 255
SMALLINT 2 -32,768 ~ 32,767 0 ~ 65,535
MEDIUMINT 3 -8,388,608 ~ 8,388,607 0 ~ 16,777,215
INT 4 -2,147,483,648 ~ 2,147,483,647 0 ~ 4,294,967,295
BIGINT 8 -9223372036854775808
~ 9223372036854775807
0 ~ 18446744073709551615

 

  • 문자 자료형
자료형 설명 차지하는 바이트 최대 바이트
CHAR( s ) s만큼 고정 사이즈 (스페이스로 채움) s (고정값) 255
VARCHAR ( s ) 가변 사이즈 S이 0~255 이면 문자길이+1byte,
~ 65,535 이면 문자길이+2byte
65,535
자료형 최대 바이트 크기
TINYTEXT 255
TEXT 65,535
게시글 또는 신문기사 같은 긴글 (자주 검색시 varchar보다 느림)
MEDIUMTEXT 16,777,215
LONGTEXT 4,294,967,295

 

  • 시간 자료형
자료형 설명 비고
DATE YYYY-MM-DD 3 Byte, 1000-01-01 ~ 9999-12-31
TIME HHH:MI:SS HHH: -838 ~ 838까지의 시간
DATETIME YYYY-MM-DD HH:MI:SS 8 Byte, 입력된 시간을 그 값 자체로 저장
1000-01-01 00:00:00 ~ 9999-12-31 23:59:59
TIMESTAMP YYYY-MM-DD HH:MI:SS 4 Byte, MySQL이 설치된 컴퓨터의 시간대를 기준으로 저장
1970-01-01 00:00:00 ~ 2037-01-19 03:14:07
  • datetime: 국내 서비스에 적합
  • timestamp: 국제 서비스에 적합

 

 

3. 테이블

 3-1) 생성 ㄱ 

더보기
drop table if exists member;
create table member(
	M_id int auto_increment primary key,
	M_nick varchar(20) unique not null,
	M_name varchar(20) not null,
	M_age tinyint unsigned default 0 not null,
	M_birth date default (current_date) not null 
);
desc member;
select*from member;
  • 테이블을 만들기 전, 테이블이 이미 있을 수 있으므로 테이블이 존재한다면, 삭제한다는 코드를 추가한다. (drop table if exists)
  • desc member: 테이블 구조를 확인한다.
  • select*from member: 테이블에 있는 모든 칼럼과 데이터를 확인한다.

 

  • current_date / curdate는 아직 잘 모르는 코드

 

  • 생성 시 제약
  • auto_increment: 새 행 생성 시마다 자동으로 1씩 증가 (1부터 시작)
  • primary key: 중복 입력이 불가능하고, null(빈 값)이 불가능하다. 테이블에 하나만 존재할 수 있다.
  • unique: 중복 입력이 불가능하다.
  • not null: null(빈 값) 입력이 불가능하다.
  • unsigned: (숫자일시) 양수만 입력이 가능하다.
  • default: 값 입력이 없을 시 기본 값을 넣는다.

 

 3-2) 추가 ㄱ 

더보기
  • DML) insert
insert into member(M_id, M_nick, M_name, M_age, M_birth)
			values(null, '1st', '첫번째친구', 10, '2023/10/26');
insert into member(M_nick, M_name, M_age, M_birth)
			values('2nd', '두번째친구', 10, curdate());
insert into member(M_nick, M_name, M_birth)
			values('3rd', '세번째친구', now());
insert into member values(null, '4th', '네번째친구', default, default);
insert into member values(null, '5th', '다섯번째친구', default, default);
  • 테이블 이름 뒤 괄호 안에 칼럼을 적고, values 뒤 괄호에는 앞서 적은 칼럼의 순서대로 데이터를 입력한다.
  • id는 자동으로 입력이 되므로 null 값을 넣어도 알아서 값이 입력된다.
  • 테이블 이름 뒤에 괄호 없이 바로 values가 와도 테이블을 생성할 때 입력한 칼럼 순으로 데이터를 입력해도 문제없다.
  • M_age와 M_birth는 default 값이 있었기 때문에 default로 입력하면 default 값이 자동으로 입력된다.

 

 3-3) 업데이트/수정 ㄱ 

더보기
  • DML) update
update member set M_name='n번째친구';		-- 1
update member set M_name='n번째친구' where M_id=1;	-- 2
-- update member set M_age+=10;	-- 3
update member set M_age=M_age+10 where M_id=3;	-- 4

-- 첫번째 나이 10% 증가
update member set M_age=M_age*1.1 where M_id=1;
  • 1번 코드처럼 작성하면 member 테이블에 있는 M_name은 모두 'n번째친구'로 데이터가 바뀌어버린다.
  • 2번 코드처럼 where절에 조건을 줘서 바꿔줘야 한다.
  • 3번 코드처럼 자바에서 사용하던 += 연산은 불가능하다. 10을 더하고 싶다면 4번 코드처럼 작성해야 한다.
  • 마지막 코드는 %를 사용하지 못하기 때문에 곱하기(*)를 이용하여 계산해주어야 한다.

 

  • where절에서 조건을 줄 때 primary key로 주는 것이 바꾸려는 안전하게 데이터만 바꿀 수 있고, 에러가 나지 않을 수 있다. (중복값이 있을 수 있기 때문에)
  • 한 번에 여러 값을 변경할 수도 있다.

 

 3-4) 삭제 ㄱ 

더보기
  • DML) delete
delete from member;
delete from member where M_id=5;
  • 위 코드처럼 작성하면 member 테이블에 있는 모든 데이터가 삭제된다.
  • where절에 삭제할 데이터 조건을 주어야 한다.

 

 3-5) 제약조건 설정 ㄱ 

더보기
drop table if exists board;
create table board(
	B_no int auto_increment,
	B_title varchar(100) not null,
	B_contents varchar(10000) not null,
	B_nick varchar(20) not null,
	B_date datetime default current_timestamp,
	-- 테이블 단ㄱ 
	primary key(B_no),
	constraint UQ_B_Nick unique(B_nick)
);
  • 제약 조건은 테이블의 단에 설정한다. (칼럼을 설정하면서 할 수도 있다.)
  • 제약 조건을 이름으로 설정하면 나중에 다시 제약 조건을 재설정할 수 있게 된다.
  • primary key는 이름을 설정할 수 없다. (Oracle에서는 가능)

 

-- 제약조건 삭제
alter table board drop constraint UQ_B_Nick;
alter table board drop primary key;		-- 기본키 삭제
  • 설정한 제약 조건 이름을 적어야 한다.
  • 기본 키인 primary key는 삭제할 수 있지만, auto_increment 설정 시 삭제할 수 없다.

 

-- 제약조건 추가
alter table board add constraint UQ_B_Nick unique(B_nick);
alter table board add primary key(B_no);
  • 설정할 제약 조건과 제약 조건 이름을 적는다.
  • primary key도 가능

 

-- 제약조건 확인
select*from information_schema.table_constraints;
  • 설정해둔 제약 조건들을 확인할 수 있다.

 

 

4. commit / rollback

더보기
  • commit: 작업 완료 / 하드디스크에 데이터를 저장
  • rollback: 가장 최근에 commit한 상태로 돌아감 (ctrl + z가 아님!)
  • 기본적으로 autocommit이 설정되어있기 때문에 해제해주어야 한다.
  • DML(데이터 조작어: insert, update, delete)만 적용한다.

 

select @@autocommit;			-- auto commit 확인용
  • autocommit이 켜져있다면 1, 아니라면 0이 출력된다.

 

set autocommit = 1;		-- autocommit 설정
set autocommit = 0;		-- autocommit 해제
  • autocommit을 켜려면 1, 아니라면 0으로 한다.

 

autocommit 완전 끄기
  • MySQL을 켤 때 autocommit이 자동으로 켜지는데 이것을 끄는 방법이다.

 

 


 

질문한 내용이나 어려웠던 점 메모

1. 그룹화

  • 그룹화를 하면 select에 그룹화 하지 않은 칼럼을 적을 수 없다는 것을 자꾸 까먹는다.

 


728x90
1 ··· 3 4 5 6 7 8 9 ··· 27