5월 12일 학습 내용 정리
Oracle / JDBC
1. Oracle
- like 'Pattern'
: pattern에 두가지 와일드카드를 사용함( % / _ )
* % : 길이와 상관 없이(0개 이상) 모든 문자 데이터를 의미
* _ : 어떤 값이든 상관 없이 한개의 문자 데이터를 의미
-- 성이 이씨인 사원 조회
select ename
from emp
-- where ename = '이'; -- 이름이 "이"인 사원
-- where ename like '이_'; -- 이름이 외자인 사원
where ename like '이%';
-- 이름이 "랑"으로 끝나는 사원
select ename
from emp
where ename like '%랑';
-- 이름에 "성"이 들어가는 사원
select ename
from emp
where ename like '%성%';
-- 이름이 "성"으로 끝나는데, 전체 이름이 3글자인 사원
-- '%성' (x)
select ename
from emp
where ename like '__성';
* not like 'Pattern'
: pattern의 반대로 사용
-- 이름에 "성"이 들어가지 않은 사원
select ename
from emp
where ename not like '%성%';
- is null
* null 여부를 확인하는 연산자
* null : 현재 무슨 값인지 확정되지 않은 상태(undefined) 또는 값 자체가 존재하지 않는 상태
-- 커미션이 null인 사원
select ename, comm
from emp
-- where comm = null; -- (x)
where comm is null; -- 값이 없기 때문에 =로 비교할 수 없음. is null을 사용해야 함
-- 커미션이 결정된 사원(comm 컬럼 값이 null이 아닌 경우)
select ename, comm
from emp
where comm is not null; -- comm이 0인 사원은 0으로 결정된 것
- order by ColumnName SortKeyword
* 정렬방식: asc(오름차순-기본값_ascending) / desc(내림차순_descending)
* 원하는 순서로 출력 데이터 정렬
-- 급여를 적게 받는 사원부터 많이 받는 사원 순으로 정렬
select ename, sal
from emp
order by sal; -- order by sal asc;(오름차순은 정렬방식 생략 가능)
-- 급여 많은 사원부터 적게 받는 순으로 정렬
select ename, sal
from emp
order by sal desc;
-- 사원 이름 순 정렬(문자 데이터는 사전순으로 정렬)
select ename
from emp
order by ename;
-- 입사일 순으로 정렬
select ename, hiredate
from emp
order by hiredate;
-- n차 정렬: 1차 정렬한 데이터 값이 동일할 때 그 이후의 정렬 순서 결정(,로 구분하여 작성)
select ename, sal
from emp
-- order by sal, ename; -- 급여가 같은 경우 이름순 정렬
order by sal asc, ename desc; -- 급여순 정렬, 급여가 같으면 이름의 역순으로 정렬
-- (헷갈릴 수 있으니 asc도 작성해주는 것이 좋음)
- desc
: 테이블 구조 확인(describe)
- create table TableName(ColumnName DataType(length))
: 테이블 생성. 여러 개 입력 시 ,로 구분
create table emp01(
empno number(4), -- 들여쓰기 필수는 아님
ename varchar2(20), -- 저장공간 가변
sal number(7, 3) -- 7자리, 소수점 이하 3자리
);
desc emp01; -- emp01 테이블의 구조 확인
- alter table TableName add ColumnName DataType
: 테이블에 컬럼 추가(= 테이블 구조 변경)
alter table emp01
add birth date;
- alter table TableName drop column ColumnName
: 테이블에서 컬럼 삭제(= 테이블 구조 변경)
alter table emp01
drop column ename; -- 데이터 타입은 작성하지 않음
- alter table TableName modify ColumnName DataType(length)
: 테이블의 컬럼 변경(= 테이블 구조 변경)
alter table emp01
modify empno number(5);
alter table emp
modify empno number(3); -- 기존에 존재하는 데이터(4자리)에 따라 테이블 변경이 안될 수도 있음
- rename A to B
: 테이블명을 A에서 B로 변경
- drop table TableName
: 객체(테이블) 제거
drop table emp02;
desc emp02; -- ERROR : emp02 객체가 존재하지 않습니다.
- insert into TableName(columnName) values(data)
: 데이터 삽입(추가)
insert into dept01
(deptno, dname, loc) -- 생성할 때 입력한 순서와 상관 없음
values
(10, '경리부', '서울'); -- insert에 작성한 순서와 동일해야 함
-- ColumnName을 생략하고 작성 가능(조회했을 때 컬럼 순서대로 value 작성해야 함)
insert into dept01
values (30, '전산부', '부산');
-- 특정 column의 값만 입력할 경우(입력하지 않은 부분은 null)
insert into dept01
(deptno, dname)
values
(40, '인사부');
-- 값을 null로 입력하여 작성해도 됨
insert into dept01
values (50, '총무부', null);
- update TableName set ColumnName = Value where Conditions
: 데이터 수정(갱신)
update dept01
set dname = '생산부'
where deptno = 10; -- deptno가 10인 dname을 생산부로 변경(where 생략 시 dname 전체가 변경됨)
- delete [from] TableName where Conditions
: 데이터 삭제
delete dept01
where deptno = 10;
- 테이블 구조만 복사하여 테이블 새로 생성하기
create table dept01
as
select * from dept
where 0 = 1; -- 무조건 거짓 -> 데이터는 가져오지 않음
- 데이터 처리는 모두 행 단위로 실행. 1행 3열의 값을 바꾸고 싶음 -> 데이터 삭제가 아닌 업데이트
- 테이블 / 데이터 처리 명령어
Table | Data | |
Create | create | insert |
Read | desc | select |
Update | alter | update |
Delete | drop | delete |
- 기타 참고사항
* 명령어는 대소문자를 구분하지 않음
* [] 안의 내용은 생략이 가능
* Oracle은 utf-8로 작성. 영문자 1byte, 한글 3bytes
2. JDBC
- JDBC : Java DataBase Connectivity
자바에서 데이터베이스에 접속할 수 있도록 하는 자바 API
- JFrame과 JDBC를 활용하여 사내 직원 정보 입력/수정/삭제/조회/검색 기능 구현
// 데이터 한 건(1 row)에 대한 정보를 가지는 클래스
public class DeptVo {
// VO(Value Object): Java Bean으로 작성
/* Java Bean: 특정한 정보(id, password, name etc)를 가지고 있는 클래스를 표현하는 하나의 규칙
* 데이터를 표현하기 위한 목적을 가짐
* 이러한 규칙을 지닌 클래스 -> Java Bean
* Java Bean의 몇가지 규약을 지켜서 작성해야 함(멤버변수 private 지정, 외부 접근을 위한 getter setter 메소드 정의 등)
*/
private int deptno;
private String dname;
private String loc;
public DeptVo() { super(); }
public DeptVo(int deptno, String dname, String loc) {
super();
this.deptno = deptno;
this.dname = dname;
this.loc = loc;
}
public int getDeptno() {
return deptno;
}
public void setDeptno(int deptno) {
this.deptno = deptno;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
public String getLoc() {
return loc;
}
public void setLoc(String loc) {
this.loc = loc;
}
@Override
public String toString() {
return "DeptVo [deptno=" + deptno + ", dname=" + dname + ", loc=" + loc + "]";
}
}
// 데이터베이스에 접근(데이터베이스 담당자)하는 클래스
public class DeptDao { // DAO(Data Access Object)
// <참고> ctrl + shift + x : 대문자로 변경 / ctrl + shift + y : 소문자로 변경
// 데이터베이스 접근을 위한 변수(id, pw, driver, url)는 private final로 정의해야 함
private final String ID = "user01";
private final String PW = "1234"; // ID & PW: Oracle에서 미리 설정해 놓은 user의 정보
private final String DRIVER = "oracle.jdbc.driver.OracleDriver";
private final String URL = "jdbc:oracle:thin:@localhost:1521:xe"; // localhost -> ip부분
// 싱글톤(담당자만 접근하도록 해야 함)
private static DeptDao instance = new DeptDao();
private DeptDao() {/* Singleton */}
public static DeptDao getInstance() {
return instance;
}
// 커넥션 얻기
private Connection getConnection() {
try {
Class.forName(DRIVER); // driver 이름을 잘못 입력할 수도 있기 때문에 발생하는 오류 처리 필요
Connection conn = DriverManager.getConnection(URL, ID, PW);
return conn;
} catch (Exception e) {
e.printStackTrace();
}
return null; // 참조형의 기본값 null(문제 발생 시 conn이 아닌 null 반환)
}
// CRUD 작업에서 공통적으로 필요한 메서드(close) 만들기
// 예외처리가 필요해 코드가 복잡해질 수 있으니 따로 메서드를 만드는 것
private void closeAll(Connection conn, PreparedStatement pstmt, ResultSet rs) {
if (rs != null) try { rs.close(); } catch (Exception e) {}
if (pstmt != null) try { rs.close(); } catch (Exception e) {}
if (conn != null) try { rs.close(); } catch (Exception e) {}
}
// 데이터 입력
public boolean insert(DeptVo vo) { // 입력이 잘 되었는지 확인을 위해 boolean 타입 사용
Connection conn = null;
PreparedStatement pstmt = null; // 데이터 입력을 위해 필요한 Connection, PreparedStatement
try {
conn = getConnection(); // 접속하기
String sql = "insert into dept01" // 실행할 문장 만들기
+ " (deptno, dname, loc)" // 앞에 띄어쓰기가 없으면 dept01deptno 이런식으로 작성돼 에러 발생
+ " values (?, ?, ?)"; // 값 3개가 들어가는 것 표현. ;는 자동으로 추가됨
pstmt = conn.prepareStatement(sql); // 문장을 실행할 pstmt 얻기
pstmt.setInt(1, vo.getDeptno()); // 첫번째 물음표의 값 설정
pstmt.setString(2, vo.getDname()); // setString을 사용하면 ''를 자동으로 설정해줌
pstmt.setString(3, vo.getLoc());
int count = pstmt.executeUpdate();
/* executeUpdate: select문을 제외한 다른 구문(insert, update, delete)을 실행할 때 사용하는 함수
* 몇개의 행에 변경사항이 있는지에 대한 값 반환(변경이 적용된 기록 건수 반환) */
if (count == 1) { // count > 0 으로 작성해도 됨(메서드가 제대로 실행된다면 최소 1건 이상이 변경될 것이기 때문)
return true;
}
} catch (Exception e) {
e.printStackTrace(); // 연습단계라 예외는 간단하게 처리함
} finally {
closeAll(conn, pstmt, null); // 이 메서드에서 ResultSet은 사용되지 않았으므로 null로 작성
}
return false; // 입력이 제대로 되지 않았을 때 false 반환
}
// 데이터 수정
public boolean update(DeptVo vo) { // 수정이 잘 되었는지 확인을 위해 boolean 타입 사용
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = getConnection();
String sql = "update dept01 set"
+ " dname = ?,"
+ " loc = ?"
+ " where deptno = ?";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, vo.getDname());
pstmt.setString(2, vo.getLoc());
pstmt.setInt(3, vo.getDeptno());
int count = pstmt.executeUpdate();
if (count > 0) {
return true;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
closeAll(conn, pstmt, null);
}
return false;
}
// 데이터 삭제
public boolean delete(int deptno) {
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = getConnection();
String sql = "delete dept01"
+ " where deptno = ?";
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, deptno);
int count = pstmt.executeUpdate();
if (count > 0) {
return true;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
closeAll(conn, pstmt, null);
}
return false;
}
// 데이터 조회
public Vector<DeptVo> selectAll() {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null; // 데이터를 조회하려면 결과를 담을 ResultSet 필요
try {
conn = getConnection();
String sql = "select *"
+ " from dept01"
+ " order by deptno";
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery(); // executeupdate가 아님. executeQuery: select문을 실행할 때 사용하는 함수
Vector<DeptVo> vec = new Vector<>();
while (rs.next()) { // 다음에 읽을 행이 있다면 true, 아니면 false 반환
int deptno = rs.getInt("deptno");
String dname = rs.getString("dname");
String loc = rs.getString("loc"); // deptno, dname, loc이 데이터 한 건
DeptVo vo = new DeptVo(deptno, dname, loc);
vec.add(vo); // 데이터들을 담을 공간
}
return vec; // while문 안에 작성하지 않도록 주의
} catch (Exception e) {
e.printStackTrace();
} finally {
closeAll(conn, pstmt, rs);
}
return null;
}
// 데이터 검색
public Vector<DeptVo> search(String col, String keyword) { // 파라미터: 컬럼, 검색어
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = getConnection();
String sql = "select * from dept01"
+ " where " + col + " like '%" + keyword + "%'"; // 검색 옵션과 검색어가 필요함
/* col을 ?를 쓰면 쿼리가 자동으로 ''을 추가해서 에러 발생
* sql 부분 띄어쓰기 주의!!!!!! */
System.out.println(sql);
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
Vector<DeptVo> vec = new Vector<>();
while (rs.next()) {
int deptno = rs.getInt("deptno");
String dname = rs.getString("dname");
String loc = rs.getString("loc");
DeptVo vo = new DeptVo(deptno, dname, loc);
vec.add(vo);
}
return vec;
} catch (Exception e) {
e.printStackTrace();
} finally {
closeAll(conn, pstmt, rs);
}
return null;
}
}
public class DeptFrame extends JFrame implements ActionListener {
DeptDao dao;
Container c = getContentPane();
InputDialog dialog = new InputDialog();
JButton btnInsert = new JButton("입력");
JButton btnUpdate = new JButton("수정");
JButton btnDelete = new JButton("삭제");
JButton btnSelect = new JButton("조회");
JButton btnSearch = new JButton("검색");
JComboBox<String> cbSearch = new JComboBox<>(new String[] {
"부서번호", "부서명", "지역"
});
JTextField tfSearch = new JTextField(10);
JTextArea taResult = new JTextArea();
public DeptFrame(DeptDao dao) {
this.dao = dao;
setDefaultCloseOperation(EXIT_ON_CLOSE);
setTitle("부서 정보");
setSize(600, 500);
setUI();
setListener();
setVisible(true);
}
private void setListener() {
btnInsert.addActionListener(this);
btnUpdate.addActionListener(this);
btnDelete.addActionListener(this);
btnSelect.addActionListener(this);
btnSearch.addActionListener(this);
tfSearch.addActionListener(this);
}
private void setUI() {
JPanel panel = new JPanel();
panel.setBackground(Color.YELLOW);
panel.add(btnInsert);
panel.add(btnUpdate);
panel.add(btnDelete);
panel.add(btnSelect);
panel.add(cbSearch);
panel.add(tfSearch);
panel.add(btnSearch);
panel.add(taResult);
c.add(panel, BorderLayout.NORTH);
c.add(new JScrollPane(taResult));
}
public static void main(String[] args) {
new DeptFrame(DeptDao.getInstance());
// 전략패턴: 어떤 파라미터를 쓸 지 메인에서 결정함
// 프레임에서 얻어도 결과는 동일함(사용하는 패턴이 다른 것 뿐)
}
private void showResult(Vector<DeptVo> vec) { // search와 select에서 반복되는 작업이라 메서드 처리
taResult.setText("");
for (DeptVo vo : vec) {
StringBuffer sb = new StringBuffer();
sb.append(vo.getDeptno()); sb.append(" | ");
sb.append(vo.getDname()); sb.append(" | ");
sb.append(vo.getLoc()); sb.append("\n");
taResult.append(sb.toString());
}
}
public class InputDialog extends JDialog implements ActionListener { // 데이터 입력 시 사용할 팝업창
JTextField tfDeptno = new JTextField();
JTextField tfDname = new JTextField();
JTextField tfLoc = new JTextField();
JButton btnOk = new JButton("확인");
JButton btnCancel = new JButton("취소");
public InputDialog() {
setModal(true); // 다이얼로그 창을 처리하지 않으면 다른 작업을 실행하지 못하도록 설정
setLayout(new GridLayout(4, 2));
setTitle("입력");
setSize(300, 200);
this.setUI();
this.setListener();
}
private void setListener() {
btnOk.addActionListener(this);
btnCancel.addActionListener(this);
}
private void setUI() {
add(new JLabel("부서번호:"));
add(tfDeptno);
add(new JLabel("부서명:"));
add(tfDname);
add(new JLabel("지역:"));
add(tfLoc);
add(btnOk);
add(btnCancel);
}
@Override
public void actionPerformed(ActionEvent e) { // 다이얼로그 액션 처리
Object obj = e.getSource();
if (obj == btnOk) {
String title = getTitle(); // 입력/수정에 따라 다른 작업 처리를 위함
int deptno = Integer.parseInt(tfDeptno.getText());
String dname = tfDname.getText();
String loc = tfLoc.getText();
DeptVo vo = new DeptVo(deptno, dname, loc);
boolean result = false;
if (title.equals("입력")) result = dao.insert(vo);
else if (title.equals("수정")) result = dao.update(vo);
if (result) JOptionPane.showMessageDialog(this, title + " 성공",
"결과", JOptionPane.DEFAULT_OPTION);
else JOptionPane.showMessageDialog(this, title + " 실패",
"결과", JOptionPane.DEFAULT_OPTION);
setVisible(false);
} else if (obj == btnCancel) {
setVisible(false);
}
}
}
@Override
public void actionPerformed(ActionEvent e) {
Object obj = e.getSource();
if (obj == btnInsert) {
dialog.setTitle("입력");
dialog.setVisible(true);
} else if (obj == btnUpdate) {
dialog.setTitle("수정");
dialog.setVisible(true);
} else if (obj == btnDelete) {
String input = JOptionPane.showInputDialog(this,
"삭제할 부서번호를 입력하세요.", "삭제",
JOptionPane.QUESTION_MESSAGE);
int deptno = Integer.parseInt(input);
boolean result = dao.delete(deptno);
String message = "";
if (result) {
message = "삭제 성공";
} else {
message = "삭제 실패";
}
JOptionPane.showMessageDialog(this, message,
"삭제 결과", JOptionPane.DEFAULT_OPTION);
} else if (obj == btnSelect) {
Vector<DeptVo> vec = dao.selectAll();
showResult(vec);
} else if (obj == btnSearch || obj == tfSearch) {
String item = (String)cbSearch.getSelectedItem(); // 콤보박스에서 선택된 글자 얻기
String col = "";
switch (item) {
case "부서번호" :
col = "deptno";
break;
case "부서명" :
col = "dname";
break;
case "지역" :
col = "loc";
break;
}
String keyword = tfSearch.getText();
Vector<DeptVo> vec = dao.search(col, keyword);
showResult(vec);
}
}
}
// 테스트 코드
public class DeptDaoTest {
private static DeptDao dao = DeptDao.getInstance();
public static void main(String[] args) {
// testInsert(); // Oracle에서 조회해보면 DeptVo 생성자의 파라미터 값이 들어가 있음
// testUpdate();
// testDelete();
// insertTestData();
// testSelectAll();
testSearch();
}
private static void testInsert() {
DeptVo vo = new DeptVo(10, "경리부", "서울"); // 실제로는 사용자에게 입력을 받겠지만 테스트를 위해 임의로 생성
boolean result = dao.insert(vo);
System.out.println(result);
}
private static void testUpdate() {
DeptVo vo = new DeptVo(10, "인사부", "부산");
boolean result = dao.update(vo);
System.out.println(result);
}
private static void testDelete() {
int deptno = 10;
boolean result = dao.delete(deptno);
System.out.println(result);
}
private static void insertTestData() { // 미리 데이터를 입력해놓고 테스트하면 편하게 코드를 작성할 수 있음
for (int i = 1; i < 10; i++) {
DeptVo vo = new DeptVo(10 * i, "경리부" + i, "서울" + i);
boolean result = dao.insert(vo);
System.out.println(result);
}
}
private static void testSelectAll() {
Vector<DeptVo> vec = dao.selectAll();
System.out.println(vec); // DeptVo에서 toString을 오버라이딩하여 원하는 형식으로 출력됨
}
private static void testSearch() {
Vector<DeptVo> vec = dao.search("dname", "부7");
System.out.println(vec);
}
}
'Daily Record' 카테고리의 다른 글
[JDBC/활용] SQL과 JFrame으로 CRUD 구현하기 (0) | 2023.05.22 |
---|---|
5월 3주차 학습 내용 정리 (0) | 2023.05.20 |
5월 11일 학습 내용 정리 (0) | 2023.05.11 |
5월 10일 학습 내용 정리 (0) | 2023.05.10 |
5월 9일 학습 내용 정리 (0) | 2023.05.09 |
Liked this Posting!