요약정리
평가 시험
dept
employee
https://oper6210.tistory.com/149
left, right, inner, outer, natural join
left, right, inner, outer join에 대해서 알아보자. 위의 join 들을 검색했을 때 가장 많이 나오는 사진은 다음과 같다. 결과 부터 말하자면 INNER JOIN은 JOIN과 같은 말이고 LETF JOIN과 LETF OUTER JOIN도 같..
oper6210.tistory.com
하이버네이트라는게 있음
쿼리문 없이 만들 수 있지만, 복잡한 것을 못짬
JPA
PL/SQL 프로시저 같은 것. 프로그램이나 함수 같은 것(근데 요새 안쓰는 추새)
이걸로 반복문 돌려서 등록을 여러개 할 수 있음.
일반 프로그래밍 언어 요소를 다 갖고 있으며, 데이터베이스 업무를 처리하기 위한 최적화된 언어
BLOCK 구조로 다수의 SQL 문을 한번에 처리하므로 수행 속도가 빠름
프로시저 특징
반환값이 없다.(RETURN이 없다.)
board upsert 만들고 vscode에서 직접 기입 해보고 apptest까지 마침
오전일과
학생테이블에는 강의실이 없는 것을 등록할 수 없음.
외래키를 ABC만 넣어서 F 넣음
(insert로 commit 했다는 것)
JOIN은 개념정리의 url 보면 됨.
INNER JOIN이 교집합임 이걸 가장 많이 씀.(많은 테이블을 들고올땐 아래 VIEW)
합쳐서 들고오기
SELECT C.*, S.* FROM CLASSTBL C, STUDENTTBL S WHERE C.CLSCODE=S.STDCLASS;
-- ANSI 표준 SQL
SELECT C.*, S.* FROM CLASSTBL C
INNER JOIN STUDENTTBL S ON C.CLSCODE=S.STDCLASS;
SELECT C.CLSCODE, C.CLSNAME, S.STDNO, S.STDNAME FROM CLASSTBL C
INNER JOIN STUDENTTBL S ON C.CLSCODE=S.STDCLASS;
-- RIGHT OUTER JOIN == INNER JOIN 여기서는 두개가 같음
SELECT C.*, S.* FROM STUDENTTBL S, CLASSTBL C WHERE C.CLSCODE=S.STDCLASS(+);
SELECT S.*, C.* FROM STUDENTTBL S, CLASSTBL C WHERE C.CLSCODE=S.STDCLASS(+);
SELECT C.*, S.* FROM STUDENTTBL S, CLASSTBL C WHERE C.CLSCODE(+)=S.STDCLASS;
SELECT S.*, C.* FROM STUDENTTBL S, CLASSTBL C WHERE C.CLSCODE(+)=S.STDCLASS;
SELECT S.*, C.* FROM STUDENTTBL S RIGHT OUTER JOIN CLASSTBL C ON C.CLSCODE=S.STDCLASS;
--FULL OUTER JOIN
SELECT S.*, C.* FROM STUDENTTBL S FULL OUTER JOIN CLASSTBL C ON C.CLSCODE=S.STDCLASS; -- ANSI 표준
4~5개이상 테이블을 여러개 들고오려하면 렉이 걸릴 수 있음.
그래서 뷰를 만들어봄(그대신 뷰는 조회만 가능)
CREATE OR REPLACE VIEW CLASS_STUDENT_VIEW AS
SELECT C.CLSCODE, C.CLSNAME, S.STDNO, S.STDNAME FROM CLASSTBL C
INNER JOIN STUDENTTBL S ON C.CLSCODE=S.STDCLASS;
-- 아래 뷰는 조회만 가능함. 뷰특징이 조회만 가능한 것.
-- (아래 코드는 CLSCODE,CLSNAME,STDNO,STDNAME이 출력 되는데, 이 데이터들이 바뀌면 자동으로 바뀜)
SELECT C.* FROM CLASS_STUDENT_VIEW C;
실습함
ORDER, ITEM, MEMBER 합치기
-- 실습
-- 회원, 물품, 주문 섞기
SELECT M.* FROM MEMBERTBL M;
SELECT I.* FROM ITEMTBL I;
SELECT O.* FROM ORDERTBL O;
-- 문제 주문번호용 시퀀스 SEQ_ORDER_NO 10001
CREATE SEQUENCE SEQ_ORDER_NO START WITH 10001
INCREMENT BY 1 NOMAXVALUE NOCACHE;
-- 문제 제약조건 기본키 시퀀스, 외래키 2개의 제약조건
INSERT INTO ORDERTBL VALUES(SEQ_ORDER_NO.NEXTVAL, 100, 1003, 'a', CURRENT_DATE);
-- INNER JOIN ORDERTBL+ITEMTBL
SELECT O.*, I.* FROM ORDERTBL O INNER JOIN ITEMTBL I ON O.ITEMNO=I.NO;
SELECT O.NO, O.CNT, O.ITEMNO, O.USERID, I.NAME, I.PRICE FROM ORDERTBL O INNER JOIN ITEMTBL I ON O.ITEMNO=I.NO;
-- INNER JOUN (ORDERTBL+ITEMTBL)+MEMBERTBL
SELECT OI.*, M.* FROM (
SELECT
O.NO, O.CNT, O.ITEMNO, O.USERID,
I.NAME, I.PRICE
FROM
ORDERTBL O
INNER JOIN
ITEMTBL I
ON
O.ITEMNO = I.NO
) OI INNER JOIN MEMBERTBL M ON OI.USERID=M.USERID;
--------------------------------
SELECT OI.*, M.AGE, M.PHONE, M.GENDER FROM (
SELECT
O.NO, O.CNT, O.ITEMNO,O.USERID,
I.NAME, I.PRICE
FROM
ORDERTBL O
INNER JOIN
ITEMTBL I
ON
O.ITEMNO=I.NO
) OI INNER JOIN MEMBERTBL M ON OI.USERID=M.USERID;
-- 위에꺼 뷰로 만듬
-- view ORDER_ITEM_MEMBER_VIEW
CREATE OR REPLACE VIEW ORDER_ITEM_MEMBER_VIEW AS
SELECT OI.*, M.AGE, M.PHONE, M.GENDER FROM (
SELECT
O.NO, O.CNT, O.ITEMNO,O.USERID, O.REGDATE,
I.NAME, I.PRICE
FROM
ORDERTBL O
INNER JOIN
ITEMTBL I
ON
O.ITEMNO=I.NO
) OI INNER JOIN MEMBERTBL M ON OI.USERID=M.USERID;
-- 아래는 뷰 불러오기
SELECT OV.* FROM ORDER_ITEM_MEMBER_VIEW OV;
-- 위에꺼 페이지 네이션 할 것임. 전체에 대해 번호 부여
SELECT OV.*, ROW_NUMBER() OVER (ORDER BY OV.NO DESC) FROM ORDER_ITEM_MEMBER_VIEW OV;
SELECT ROW_NUMBER() OVER (ORDER BY OV.NO DESC) ROWN, OV.* FROM ORDER_ITEM_MEMBER_VIEW OV; -- 이거랑 물품별 번호 비교해보기
-- 물품별 번호 부여(번호 : ROW_NUMBER() 순위 : RANK())
SELECT
ROW_NUMBER() OVER (PARTITION BY OV.ITEMNO ORDER BY OV.NO DESC) ROWN,
OV.*
FROM ORDER_ITEM_MEMBER_VIEW OV;
-- 페이지네이션(생성된 것 기반으로 다시 조회하여 페이지 네이션을 만듬)
SELECT T1.* FROM(
SELECT
ROW_NUMBER() OVER (ORDER BY OV.NO DESC) ROWN,
OV.*
FROM ORDER_ITEM_MEMBER_VIEW OV
) T1
WHERE T1.ROWN BETWEEN 1 AND 3;
뷰만듬
페이지 네이션
- 전체에 대해 번호 부여
- 물품별 번호 부여 (ROW_NYMBER(), RANK())
- 페이지네이션(생성된 것 기반으로 다시 조회하여 페이지 네이션을 만듬)
- 주문개수CNT에 조건을 줘서 테이블에 A, B , C 등급 추가해줌
-- 주문수량 0~100 A등급
-- 주문수량 101~200 B등급
-- 주문수량 300이상 C등급
-- 뷰에서 일단 들고옴
SELECT OV.* FROM ORDER_ITEM_MEMBER_VIEW OV;
-- 위에꺼 만져서 아래껄로 만듬
SELECT
OV.*,
CASE
WHEN(OV.CNT >= 0 AND OV.CNT<=100) THEN 'A등급'
WHEN(OV.CNT >= 101 AND OV.CNT<=200) THEN 'B등급'
WHEN(OV.CNT >= 201) THEN 'C등급'
END GRADE,
OV.*
FROM ORDER_ITEM_MEMBER_VIEW OV;
인덱스 오류 있는 사람 있어서 인덱스 설명
-- 검색속도를 향샹시켜줌
-- 기본키는 인덱스를 자동 설정함.
-- 인덱스 생성 IDX_ITEM_NAME ON 테이블명(컬럼명);
CREATE INDEX IDX_ITEM_NAME ON ITEMTBL(NAME);
DEPT
EMPLOYEE
테이블 데이터 까지 만들어 주심 + 실습 문제
SELECT D.* FROM DEPT D;
INSERT INTO DEPT VALUES(101, '총무부', CURRENT_DATE, '서울');
INSERT INTO DEPT VALUES(102, '영업부', CURRENT_DATE, '부산');
INSERT INTO DEPT VALUES(103, '기획부', CURRENT_DATE, '대구');
INSERT INTO DEPT VALUES(104, '홍보부', CURRENT_DATE, '서울');
-- 101 총무부 서울
-- 102 영업부 부산
-- 103 기획부 대구
-- 104 홍보부 서울
-- SEQ_EMP_NO 시작숫자 10001
CREATE SEQUENCE SEQ_EMP_NO START WITH 10001 INCREMENT BY 1 NOMAXVALUE NOCACHE;
SELECT E.* FROM EMPTBL E;
INSERT INTO EMPTBL VALUES(SEQ_EMP_NO.NEXTVAL, '가나다1', 101, 3000000, CURRENT_DATE, '대리');
INSERT INTO EMPTBL VALUES(SEQ_EMP_NO.NEXTVAL, '가나다2', 102, 2800000, CURRENT_DATE, '대리');
INSERT INTO EMPTBL VALUES(SEQ_EMP_NO.NEXTVAL, '가나다3', 103, 5600000, CURRENT_DATE, '과장');
INSERT INTO EMPTBL VALUES(SEQ_EMP_NO.NEXTVAL, '가나다4', 104, 2700000, CURRENT_DATE, '대리');
INSERT INTO EMPTBL VALUES(SEQ_EMP_NO.NEXTVAL, '가나다5', 102, 3300000, CURRENT_DATE, '대리');
INSERT INTO EMPTBL VALUES(SEQ_EMP_NO.NEXTVAL, '가나다6', 101, 2250000, CURRENT_DATE, '사원');
DELETE FROM EMPTBL;
COMMIT;
실습 문제 내주심1~8
-- 문제1) DEPT의 영업부를 "대구" 나머지는 "부산"으로 변경
UPDATE DEPT SET AREA='부산' WHERE NAME!='영업부';
UPDATE DEPT SET AREA='대구' WHERE NAME='영업부';
UPDATE DEPT03 SET AREA =
CASE
WHEN (DEPTNO=102) THEN '대구'
ELSE '부산'
END;
-- 문제2) EMPLOYEE의 부서번호가 103인 항목 삭제
DELETE FROM EMPTBL WHERE DEPTNO = 103;
-- 문제3) EMPLOYEE의 영업부102 직원과 총무부101 직원의 이름, 급여, 직급을 사원번호 순으로 내림차순 조회
SELECT E.* FROM EMPTBL E;
SELECT NAME, PAY, POSITION FROM EMPTBL WHERE DEPTNO = '102' ORDER BY EMPNO DESC;
SELECT NAME, PAY, POSITION FROM EMPTBL WHERE DEPTNO = '101' ORDER BY EMPNO DESC;
SELECT E.DEPTNO, E.NAME, E.PAY, E.POSITION FROM EMPLOYEE E WHERE E.DEPTNO IN(101,102);
SELECT D.*, E.* FROM DEPT D
INNER JOIN(
SELECT E.DEPTNO, E.NAME, E.PAY, E.POSITION FROM EMPLOYEE E WHERE E.DEPTNO IN(101,102)
) E
ON D.DEPTNO=E.DEPTNO;
-- 문제4) EMPLOYEE의 급여에서 0~230 이면 5%, 231~300이면 10%, 301~400 15%, 400~ 20%의 세금을 조회(사원번호, 사원명, 급여, 세금 표시)
-- CASE사용
SELECT
E.EMPNO, E.NAME, E.PAY,
CASE
WHEN(0<=E.PAY AND E.PAY<=2300000) THEN TRUNC(E.PAY*0.05)
WHEN(2310000<=E.PAY AND E.PAY<=3000000) THEN TRUNC(E.PAY*0.1)
WHEN(3010000<=E.PAY AND E.PAY<=4000000) THEN TRUNC(E.PAY*0.15)
WHEN(4010000<=E.PAY) THEN TRUNC(E.PAY*0.2)
END TAX,
E.*
FROM EMPTBL E;
SELECT E.EMPNO, E.NAME, E.PAY,
CASE
WHEN(E.PAY >= 0 AND E.PAY<=2300000) THEN E.PAY*0.05
WHEN(E.PAY >= 2310000 AND E.PAY<=3000000) THEN E.PAY*0.1
WHEN(E.PAY >= 3010000 AND E.PAY<=4000000) THEN E.PAY*0.15
WHEN(E.PAY >= 4010000) THEN E.PAY*0.2
END TAX
FROM EMPLOYEE E;
-- 문제5) EMPLOYEE의 부서별 평균 급여와 인원수 출력
-- GROUP BY 사용
SELECT E.DEPTNO, AVG(E.PAY) DEPTAVG, COUNT(*) FROM EMPTBL E GROUP BY DEPTNO;
SELECT E.DEPTNO 부서번호, AVG(E.PAY) 평균급여, COUNT(*) 인원수 FROM EMPLOYEE E GROUP BY E.DEPTNO;
-- 문제6) EMPLOYEE의 부서별 급여 평균이 300이상인 부서 조회(부서번호, 부서명, 급여 평균)
SELECT T1.* FROM(
SELECT E.DEPTNO, AVG(E.PAY) DEPTAVG
FROM EMPTBL E
GROUP BY DEPTNO
) T1
WHERE DEPTAVG>3000000;
SELECT E.DEPTNO 부서번호, AVG(E.PAY) 평균급여 FROM EMPTBL E GROUP BY E.DEPTNO HAVING AVG(E.PAY)>=3000000;
SELECT D.* , E.* FROM DEPT D INNER JOIN (
SELECT E.DEPTNO, AVG(E.PAY) 평균급여 FROM EMPTBL E GROUP BY E.DEPTNO HAVING AVG(E.PAY)>=3000000
) E
ON D.DEPTNO = E.DEPTNO;
-- 문제7) 직급별 총급여, 평균급여, 인원수 출력
SELECT E.POSITION, SUM(E.PAY) POSITIONSUM, AVG(E.PAY) POSITIONAVG, COUNT(*) FROM EMPTBL E GROUP BY POSITION;
SELECT E.POSITION 직급, SUM(E.PAY)총급여, AVG(E.PAY) 평균급여, COUNT(*) 인원수 FROM EMPLOYEE E GROUP BY E.POSITION;
-- 문제8) 직급별 급여가 높은 순으로 RANK() 출력
-- PARTITON사용
SELECT
RANK() OVER (PARTITION BY E.POSITION ORDER BY E.PAY DESC) RANK,
E.*
FROM EMPTBL E;
SELECT
RANK() OVER (PARTITION BY E.POSITION ORDER BY E.PAY DESC) RNK,
E.*
FROM EMPLOYEE E;
문제1) DEPT의 영업부를 "대구" 나머지는 "부산"으로 변경
UPDATE DEPT SET AREA =
CASE
WHEN (DEPTNO=102) THEN '대구'
ELSE '부산'
END;
문제2) EMPLOYEE의 부서번호가 103인 항목 삭제
DELETE FROM EMPTBL WHERE DEPTNO = 103;
문제3) EMPLOYEE의 영업부102 직원과 총무부101 직원의 이름, 급여, 직급을 사원번호 순으로 내림차순 조회
SELECT E.DEPTNO, E.NAME, E.PAY, E.POSITION FROM EMPTBL E WHERE E.DEPTNO IN(101,102);
SELECT D.*, E.* FROM DEPT D
INNER JOIN(
SELECT E.DEPTNO, E.NAME, E.PAY, E.POSITION FROM EMPTBL E WHERE E.DEPTNO IN(101,102)
) E
ON D.DEPTNO=E.DEPTNO;
문제4) EMPLOYEE의 급여에서 0~230 이면 5%, 231~300이면 10%, 301~400 15%, 400~ 20%의 세금을 조회(사원번호, 사원명, 급여, 세금 표시)
SELECT E.EMPNO, E.NAME, E.PAY,
CASE
WHEN(E.PAY >= 0 AND E.PAY<=2300000) THEN E.PAY*0.05
WHEN(E.PAY >= 2310000 AND E.PAY<=3000000) THEN E.PAY*0.1
WHEN(E.PAY >= 3010000 AND E.PAY<=4000000) THEN E.PAY*0.15
WHEN(E.PAY >= 4010000) THEN E.PAY*0.2
END TAX
FROM EMPTBL E;
문제5) EMPLOYEE의 부서별 평균 급여와 인원수 출력
SELECT E.DEPTNO 부서번호, AVG(E.PAY) 평균급여, COUNT(*) 인원수 FROM EMPTBL E GROUP BY E.DEPTNO;
문제6) EMPLOYEE의 부서별 급여 평균이 300이상인 부서 조회(부서번호, 부서명, 급여 평균)
SELECT D.* , E.* FROM DEPT D INNER JOIN (
SELECT E.DEPTNO, AVG(E.PAY) 평균급여 FROM EMPTBL E GROUP BY E.DEPTNO HAVING AVG(E.PAY)>=3000000
) E
ON D.DEPTNO = E.DEPTNO;
문제7) 직급별 총급여, 평균급여, 인원수 출력
SELECT E.POSITION 직급, SUM(E.PAY)총급여, AVG(E.PAY) 평균급여, COUNT(*) 인원수 FROM EMPTBL E GROUP BY E.POSITION;
문제8) 직급별 급여가 높은 순으로 RANK() 출력
SELECT
RANK() OVER (PARTITION BY E.POSITION ORDER BY E.PAY DESC) RNK,
E.*
FROM EMPTBL E;
오후일과
PL/SQL 프로시저 같은 것. 프로그램이나 함수 같은 것
이걸로 반복문 돌려서 등록을 여러개 할 수 있음.
일반 프로그래밍 언어 요소를 다 갖고 있으며, 데이터베이스 업무를 처리하기 위한 최적화된 언어
BLOCK 구조로 다수의 SQL 문을 한번에 처리하므로 수행 속도가 빠름
시작하기전에 서버 켜야함
SET SERVEROUTPUT ON;
--서버 꺼져있어서 켜야함
출력해봄
-- 자바로 따지면 SYSO임.
BEGIN
DBMS_OUTPUT.PUT_LINE('hello');
END;
/
-- PL/SQL종료
변수선언
-- 변수도 만들 수 있음. INT A = 13;
DECLARE
V_STR VARCHAR2(30) := 'asdf'; -- 원래 이런 변수값들은 스프링 부트에서 받아야함
V_NUM NUMBER := 13;
BEGIN
DBMS_OUTPUT.PUT_LINE('str =>' || V_STR);
DBMS_OUTPUT.PUT_LINE('num =>' || V_NUM);
END;
/
IF FOR 해봄
-- IF
DECLARE
V_STR VARCHAR2(2); -- 원래 이런 변수값들은 스프링 부트에서 받아야함
V_NUM NUMBER := 90;
BEGIN
IF V_NUM >=90 THEN
V_STR := 'A';
ELSIF V_NUM >=80 THEN
V_STR := 'B';
ELSIF V_NUM >=70 THEN
V_STR := 'C';
ELSE
V_STR := 'D';
END IF;
DBMS_OUTPUT.PUT_LINE('등급은 =>' || V_STR);
END;
/
-- FOR
DECLARE
V_NUM NUMBER := 5;
BEGIN
FOR i IN 1..V_NUM LOOP
IF i =1 OR i = 3 OR i =5 THEN
DBMS_OUTPUT.PUT_LINE('반복숫자 =>' || i);
END IF;
END LOOP;
END;
/
프로시저 특징
반환값이 없다.(RETURN이 없다.)
프로시저 연습용 하나 만들었고
CREATE OR REPLACE PROCEDURE PROC_GRADE(
V_NUM IN NUMBER -- IN은 외부에서 들어가는 값
)
IS
V_NUM1 NUMBER := 5;
BEGIN
DBMS_OUTPUT.PUT_LINE('합은 =>' || (V_NUM+V_NUM1));
END;
/
EXEC PROC_GRADE(50); -- 테스트용 SPRING BOOT에서 호출해야함.
게시판으로 예제
- 게시판에 글번호가 존재하면 update를 수행,
- 존재하지 않으면 insert를 수행하는 프로시저
-------------------------------게시판 예제
CREATE OR REPLACE PROCEDURE PROC_BOARD_UPSERT(
V_NO IN BOARDTBL.NO%TYPE, --number
V_TITLE IN BOARDTBL.TITLE%TYPE,
V_CONTENT IN BOARDTBL.CONTENT%TYPE,
V_WRITER IN BOARDTBL.WRITER%TYPE,
V_RET OUT NUMBER
)
IS
V_CHK NUMBER(1) := 0; -- 존재유무 확인용
BEGIN
-- 조회한 결과를 V_CHK에 보관
SELECT COUNT(*) INTO V_CHK FROM BOARDTBL B WHERE B.NO = V_NO;
-- SELECT COUNT(*) FROM BOARDTBL B WHERE B.NO = 1;
-- SELECT COUNT(*) FROM BOARDTBL B WHERE B.NO = 1000;
IF V_CHK > 0 THEN
UPDATE BOARDTBL SET TITLE=V_TITLE, CONTENT=V_CONTENT,
WRITER=V_WRITER WHERE NO=V_NO;
V_RET := 1;
ELSE
INSERT INTO BOARDTBL(NO, TITLE, WRITER, HIT, REGDATE, CONTENT)
VALUES (SEQ_BOARDTBL_NO.NEXTVAL, V_TITLE, V_WRITER, 1, CURRENT_DATE, V_CONTENT);
V_RET := 2;
END IF;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
V_RET := 0;
ROLLBACK;
END;
/
SELECT B.* FROM BOARDTBL B;
DECLARE
V_RET NUMBER;
BEGIN
PROC_BOARD_UPSERT(100, 'PROC제목', 'PROC내용', 'PROC작성자', V_RET);
DBMS_OUTPUT.PUT_LINE('OUT변수 값은 =>' || V_RET);
END;
/
EXEC PROC_BOARD_UPSERT(15, 'PROC제목', 'PROC내용', 'PROC작성자');
게시물 조회로 있나없나확인하고
업설트 이거 중요중요중요중요중요중요중요중요중요중요중요중요
V_RET OUT
vscode로 이동
boardmapper
프로시저는 insert
BoardMapper.java
package com.example.mapper;
import java.util.Map;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.mapping.StatementType;
@Mapper
public interface BoardMapper {
@Insert({
"{ call PROC_BOARD_UPSERT(",
"#{map.no, mode=IN, jdbcType=NUMERIC, javaType=Long }, ",
"#{map.title, mode=IN, jdbcType=VARCHAR, javaType=String }, ",
"#{map.content, mode=IN, jdbcType=VARCHAR, javaType=String }, ",
"#{map.writer, mode=IN, jdbcType=VARCHAR, javaType=String }, ",
"#{map.ret, mode=OUT, jdbcType=NUMERIC, javaType=Integer }",
")}"
})
@Options(statementType = StatementType.CALLABLE)
public void callProcedure(@Param("map") Map<String, Object> map);
}
MyBoardTest.java
package com.example.boot_20220827;
import java.util.HashMap;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import com.example.mapper.BoardMapper;
import lombok.extern.slf4j.Slf4j;
@SpringBootTest
@Slf4j
public class MyBoardTest {
final String format = "BOARDTBL => {}";
@Autowired
BoardMapper bMapper;
@Test
public void selectListTest(){
log.info(format,"PROC TEST");
Map<String, Object> map = new HashMap<>();
map.put("no", 1L);
map.put("title", "제목");
map.put("content", "내용");
map.put("writer", "작성자");
map.put("ret", 0);
bMapper.callProcedure( map );
// System.out.println( "retretretretretretretretretretretretretret"+map.get("ret") );
log.info(format,map.get("ret"));
}
}
sql
-- 22_09_08 오전
SELECT C.* FROM CLASSTBL C;
SELECT S.* FROM STUDENTTBL S;
-- 합쳐서 들고오기
-- INNER JOIN
SELECT C.*, S.* FROM CLASSTBL C, STUDENTTBL S WHERE C.CLSCODE=S.STDCLASS;
-- ANSI 표쥰 SQL
SELECT C.*, S.* FROM CLASSTBL C
INNER JOIN STUDENTTBL S ON C.CLSCODE=S.STDCLASS;
SELECT C.CLSCODE, C.CLSNAME, S.STDNO, S.STDNAME FROM CLASSTBL C
INNER JOIN STUDENTTBL S ON C.CLSCODE=S.STDCLASS;
-- RIGHT OUTER JOIN == INNER JOIN 여기서는 두개가 같음
SELECT C.*, S.* FROM STUDENTTBL S, CLASSTBL C WHERE C.CLSCODE=S.STDCLASS(+);
SELECT S.*, C.* FROM STUDENTTBL S, CLASSTBL C WHERE C.CLSCODE=S.STDCLASS(+);
SELECT C.*, S.* FROM STUDENTTBL S, CLASSTBL C WHERE C.CLSCODE(+)=S.STDCLASS;
SELECT S.*, C.* FROM STUDENTTBL S, CLASSTBL C WHERE C.CLSCODE(+)=S.STDCLASS; -- 요거
SELECT S.*, C.* FROM STUDENTTBL S RIGHT OUTER JOIN CLASSTBL C ON C.CLSCODE=S.STDCLASS;
--FULL OUTER JOIN
SELECT S.*, C.* FROM STUDENTTBL S, CLASSTBL C WHERE C.CLSCODE(+)=S.STDCLASS(+); -- 이건 안됨
SELECT S.*, C.* FROM STUDENTTBL S FULL OUTER JOIN CLASSTBL C ON C.CLSCODE=S.STDCLASS; -- ANSI 표준
-- ANSI 표준 SQL
-- 조인한 결과를 기반으로 VIEW 생성 (CLASS_STUDENT_VIEW)
-- 4~5개이상 테이블을 여러개 들고오려하면 렉이 걸릴 수 있음. 그래서 아래처럼 VIEW를 씀
CREATE OR REPLACE VIEW CLASS_STUDENT_VIEW AS
SELECT C.CLSCODE, C.CLSNAME, S.STDNO, S.STDNAME FROM CLASSTBL C
INNER JOIN STUDENTTBL S ON C.CLSCODE=S.STDCLASS;
-- 아래 뷰는 조회만 가능함. 뷰특징이 조회만 가능한 것.
-- (아래 코드는 CLSCODE,CLSNAME,STDNO,STDNAME이 출력 되는데, 이 데이터들이 바뀌면 자동으로 바뀜)
SELECT C.* FROM CLASS_STUDENT_VIEW C;
-- 실습
-- 회원, 물품, 주문 섞기
SELECT M.* FROM MEMBERTBL M;
SELECT I.* FROM ITEMTBL I;
SELECT O.* FROM ORDERTBL O;
-- 문제 주문번호용 시퀀스 SEQ_ORDER_NO 10001
CREATE SEQUENCE SEQ_ORDER_NO START WITH 10001
INCREMENT BY 1 NOMAXVALUE NOCACHE;
-- 문제 제약조건 기본키 시퀀스, 외래키 2개의 제약조건
INSERT INTO ORDERTBL VALUES(SEQ_ORDER_NO.NEXTVAL, 100, 1003, 'a', CURRENT_DATE);
-- INNER JOIN ORDERTBL+ITEMTBL
SELECT O.*, I.* FROM ORDERTBL O INNER JOIN ITEMTBL I ON O.ITEMNO=I.NO;
SELECT O.NO, O.CNT, O.ITEMNO, O.USERID, I.NAME, I.PRICE FROM ORDERTBL O INNER JOIN ITEMTBL I ON O.ITEMNO=I.NO;
-- INNER JOUN (ORDERTBL+ITEMTBL)+MEMBERTBL
SELECT OI.*, M.* FROM (
SELECT
O.NO, O.CNT, O.ITEMNO, O.USERID,
I.NAME, I.PRICE
FROM
ORDERTBL O
INNER JOIN
ITEMTBL I
ON
O.ITEMNO = I.NO
) OI INNER JOIN MEMBERTBL M ON OI.USERID=M.USERID;
--------------------------------
SELECT OI.*, M.AGE, M.PHONE, M.GENDER FROM (
SELECT
O.NO, O.CNT, O.ITEMNO,O.USERID,
I.NAME, I.PRICE
FROM
ORDERTBL O
INNER JOIN
ITEMTBL I
ON
O.ITEMNO=I.NO
) OI INNER JOIN MEMBERTBL M ON OI.USERID=M.USERID;
-- 위에꺼 뷰로 만듬
-- view ORDER_ITEM_MEMBER_VIEW
CREATE OR REPLACE VIEW ORDER_ITEM_MEMBER_VIEW AS
SELECT OI.*, M.AGE, M.PHONE, M.GENDER FROM (
SELECT
O.NO, O.CNT, O.ITEMNO,O.USERID, O.REGDATE,
I.NAME, I.PRICE
FROM
ORDERTBL O
INNER JOIN
ITEMTBL I
ON
O.ITEMNO=I.NO
) OI INNER JOIN MEMBERTBL M ON OI.USERID=M.USERID;
-- 아래는 뷰 불러오기
SELECT OV.* FROM ORDER_ITEM_MEMBER_VIEW OV;
-- 위에꺼 페이지 네이션 할 것임. 전체에 대해 번호 부여
SELECT OV.*, ROW_NUMBER() OVER (ORDER BY OV.NO DESC) FROM ORDER_ITEM_MEMBER_VIEW OV;
SELECT ROW_NUMBER() OVER (ORDER BY OV.NO DESC) ROWN, OV.* FROM ORDER_ITEM_MEMBER_VIEW OV; -- 이거랑 물품별 번호 비교해보기
-- 물품별 번호 부여(번호 : ROW_NUMBER() 순위 : RANK())
SELECT
ROW_NUMBER() OVER (PARTITION BY OV.ITEMNO ORDER BY OV.NO DESC) ROWN,
OV.*
FROM ORDER_ITEM_MEMBER_VIEW OV;
-- 페이지네이션(생성된 것 기반으로 다시 조회하여 페이지 네이션을 만듬)
SELECT T1.* FROM(
SELECT
ROW_NUMBER() OVER (ORDER BY OV.NO DESC) ROWN,
OV.*
FROM ORDER_ITEM_MEMBER_VIEW OV
) T1
WHERE T1.ROWN BETWEEN 1 AND 3;
-- 주문수량 0~100 A등급
-- 주문수량 101~200 B등급
-- 주문수량 300이상 C등급
-- 뷰에서 일단 들고옴
SELECT OV.* FROM ORDER_ITEM_MEMBER_VIEW OV;
-- 위에꺼 만져서 아래껄로 만듬
SELECT
OV.*,
CASE
WHEN(OV.CNT >= 0 AND OV.CNT<=100) THEN 'A등급'
WHEN(OV.CNT >= 101 AND OV.CNT<=200) THEN 'B등급'
WHEN(OV.CNT >= 201) THEN 'C등급'
END GRADE,
OV.*
FROM ORDER_ITEM_MEMBER_VIEW OV;
-- 검색속도를 향샹시켜줌
-- 기본키는 인덱스를 자동 설정함.
-- 인덱스 생성 IDX_ITEM_NAME ON 테이블명(컬럼명);
CREATE INDEX IDX_ITEM_NAME ON ITEMTBL(NAME);
SELECT D.* FROM DEPT D;
INSERT INTO DEPT VALUES(101, '총무부', CURRENT_DATE, '서울');
INSERT INTO DEPT VALUES(102, '영업부', CURRENT_DATE, '부산');
INSERT INTO DEPT VALUES(103, '기획부', CURRENT_DATE, '대구');
INSERT INTO DEPT VALUES(104, '홍보부', CURRENT_DATE, '서울');
-- 101 총무부 서울
-- 102 영업부 부산
-- 103 기획부 대구
-- 104 홍보부 서울
-- SEQ_EMP_NO 시작숫자 10001
CREATE SEQUENCE SEQ_EMP_NO START WITH 10001 INCREMENT BY 1 NOMAXVALUE NOCACHE;
SELECT E.* FROM EMPTBL E;
INSERT INTO EMPTBL VALUES(SEQ_EMP_NO.NEXTVAL, '가나다1', 101, 3000000, CURRENT_DATE, '대리');
INSERT INTO EMPTBL VALUES(SEQ_EMP_NO.NEXTVAL, '가나다2', 102, 2800000, CURRENT_DATE, '대리');
INSERT INTO EMPTBL VALUES(SEQ_EMP_NO.NEXTVAL, '가나다3', 103, 5600000, CURRENT_DATE, '과장');
INSERT INTO EMPTBL VALUES(SEQ_EMP_NO.NEXTVAL, '가나다4', 104, 2700000, CURRENT_DATE, '대리');
INSERT INTO EMPTBL VALUES(SEQ_EMP_NO.NEXTVAL, '가나다5', 102, 3300000, CURRENT_DATE, '대리');
INSERT INTO EMPTBL VALUES(SEQ_EMP_NO.NEXTVAL, '가나다6', 101, 2250000, CURRENT_DATE, '사원');
DELETE FROM EMPTBL;
COMMIT;
--
-- 문제1) DEPT의 영업부를 "대구" 나머지는 "부산"으로 변경
UPDATE DEPT SET AREA='부산' WHERE NAME!='영업부';
UPDATE DEPT SET AREA='대구' WHERE NAME='영업부';
UPDATE DEPT03 SET AREA =
CASE
WHEN (DEPTNO=102) THEN '대구'
ELSE '부산'
END;
-- 문제2) EMPLOYEE의 부서번호가 103인 항목 삭제
DELETE FROM EMPTBL WHERE DEPTNO = 103;
-- 문제3) EMPLOYEE의 영업부102 직원과 총무부101 직원의 이름, 급여, 직급을 사원번호 순으로 내림차순 조회
SELECT E.* FROM EMPTBL E;
SELECT NAME, PAY, POSITION FROM EMPTBL WHERE DEPTNO = '102' ORDER BY EMPNO DESC;
SELECT NAME, PAY, POSITION FROM EMPTBL WHERE DEPTNO = '101' ORDER BY EMPNO DESC;
SELECT E.DEPTNO, E.NAME, E.PAY, E.POSITION FROM EMPLOYEE E WHERE E.DEPTNO IN(101,102);
SELECT D.*, E.* FROM DEPT D
INNER JOIN(
SELECT E.DEPTNO, E.NAME, E.PAY, E.POSITION FROM EMPLOYEE E WHERE E.DEPTNO IN(101,102)
) E
ON D.DEPTNO=E.DEPTNO;
-- 문제4) EMPLOYEE의 급여에서 0~230 이면 5%, 231~300이면 10%, 301~400 15%, 400~ 20%의 세금을 조회(사원번호, 사원명, 급여, 세금 표시)
-- CASE사용
SELECT
E.EMPNO, E.NAME, E.PAY,
CASE
WHEN(0<=E.PAY AND E.PAY<=2300000) THEN TRUNC(E.PAY*0.05)
WHEN(2310000<=E.PAY AND E.PAY<=3000000) THEN TRUNC(E.PAY*0.1)
WHEN(3010000<=E.PAY AND E.PAY<=4000000) THEN TRUNC(E.PAY*0.15)
WHEN(4010000<=E.PAY) THEN TRUNC(E.PAY*0.2)
END TAX,
E.*
FROM EMPTBL E;
SELECT E.EMPNO, E.NAME, E.PAY,
CASE
WHEN(E.PAY >= 0 AND E.PAY<=2300000) THEN E.PAY*0.05
WHEN(E.PAY >= 2310000 AND E.PAY<=3000000) THEN E.PAY*0.1
WHEN(E.PAY >= 3010000 AND E.PAY<=4000000) THEN E.PAY*0.15
WHEN(E.PAY >= 4010000) THEN E.PAY*0.2
END TAX
FROM EMPLOYEE E;
-- 문제5) EMPLOYEE의 부서별 평균 급여와 인원수 출력
-- GROUP BY 사용
SELECT E.DEPTNO, AVG(E.PAY) DEPTAVG, COUNT(*) FROM EMPTBL E GROUP BY DEPTNO;
SELECT E.DEPTNO 부서번호, AVG(E.PAY) 평균급여, COUNT(*) 인원수 FROM EMPLOYEE E GROUP BY E.DEPTNO;
-- 문제6) EMPLOYEE의 부서별 급여 평균이 300이상인 부서 조회(부서번호, 부서명, 급여 평균)
SELECT T1.* FROM(
SELECT E.DEPTNO, AVG(E.PAY) DEPTAVG
FROM EMPTBL E
GROUP BY DEPTNO
) T1
WHERE DEPTAVG>3000000;
SELECT E.DEPTNO 부서번호, AVG(E.PAY) 평균급여 FROM EMPTBL E GROUP BY E.DEPTNO HAVING AVG(E.PAY)>=3000000;
SELECT D.* , E.* FROM DEPT D INNER JOIN (
SELECT E.DEPTNO, AVG(E.PAY) 평균급여 FROM EMPTBL E GROUP BY E.DEPTNO HAVING AVG(E.PAY)>=3000000
) E
ON D.DEPTNO = E.DEPTNO;
-- 문제7) 직급별 총급여, 평균급여, 인원수 출력
SELECT E.POSITION, SUM(E.PAY) POSITIONSUM, AVG(E.PAY) POSITIONAVG, COUNT(*) FROM EMPTBL E GROUP BY POSITION;
SELECT E.POSITION 직급, SUM(E.PAY)총급여, AVG(E.PAY) 평균급여, COUNT(*) 인원수 FROM EMPLOYEE E GROUP BY E.POSITION;
-- 문제8) 직급별 급여가 높은 순으로 RANK() 출력
-- PARTITON사용
SELECT
RANK() OVER (PARTITION BY E.POSITION ORDER BY E.PAY DESC) RANK,
E.*
FROM EMPTBL E;
SELECT
RANK() OVER (PARTITION BY E.POSITION ORDER BY E.PAY DESC) RNK,
E.*
FROM EMPLOYEE E;
-- 08 오후일과
-- PL/SQL 프로시제 같은 것
-- 일반 프로그래밍 언어 요소를 다 갖고 있으며, 데이터베이스 업무를 처리하기 위한 최적화된 언어
-- BLOCK 구조로 다수의 SQL 문을 한번에 처리하므로 수행 속도가 빠름
SET SERVEROUTPUT ON;
--서버 꺼져있어서 켜야함
-- 자바로 따지면 SYSO임.
BEGIN
DBMS_OUTPUT.PUT_LINE('hello');
END;
/
-- PL/SQL종료
-- 변수도 만들 수 있음. INT A = 13;
DECLARE
V_STR VARCHAR2(30) := 'asdf'; -- 원래 이런 변수값들은 스프링 부트에서 받아야함
V_NUM NUMBER := 13;
BEGIN
DBMS_OUTPUT.PUT_LINE('str =>' || V_STR);
DBMS_OUTPUT.PUT_LINE('num =>' || V_NUM);
END;
/
-- IF
DECLARE
V_STR VARCHAR2(2); -- 원래 이런 변수값들은 스프링 부트에서 받아야함
V_NUM NUMBER := 90;
BEGIN
IF V_NUM >=90 THEN
V_STR := 'A';
ELSIF V_NUM >=80 THEN
V_STR := 'B';
ELSIF V_NUM >=70 THEN
V_STR := 'C';
ELSE
V_STR := 'D';
END IF;
DBMS_OUTPUT.PUT_LINE('등급은 =>' || V_STR);
END;
/
-- FOR
DECLARE
V_NUM NUMBER := 5;
BEGIN
FOR i IN 1..V_NUM LOOP
IF i =1 OR i = 3 OR i =5 THEN
DBMS_OUTPUT.PUT_LINE('반복숫자 =>' || i);
END IF;
END LOOP;
END;
/
-- 프로시저
-- 없으면 추가 있으면 수정
CREATE OR REPLACE PROCEDURE PROC_GRADE(
V_NUM IN NUMBER -- IN은 외부에서 들어가는 값
)
IS
V_NUM1 NUMBER := 5;
BEGIN
DBMS_OUTPUT.PUT_LINE('합은 =>' || (V_NUM+V_NUM1));
END;
/
EXEC PROC_GRADE(50); -- 테스트용 SPRING BOOT에서 호출해야함.
-------------------------------게시판 예제
CREATE OR REPLACE PROCEDURE PROC_BOARD_UPSERT(
V_NO IN BOARDTBL.NO%TYPE, --number
V_TITLE IN BOARDTBL.TITLE%TYPE,
V_CONTENT IN BOARDTBL.CONTENT%TYPE,
V_WRITER IN BOARDTBL.WRITER%TYPE,
V_RET OUT NUMBER
)
IS
V_CHK NUMBER(1) := 0; -- 존재유무 확인용
BEGIN
-- 조회한 결과를 V_CHK에 보관
SELECT COUNT(*) INTO V_CHK FROM BOARDTBL B WHERE B.NO = V_NO;
-- SELECT COUNT(*) FROM BOARDTBL B WHERE B.NO = 1;
-- SELECT COUNT(*) FROM BOARDTBL B WHERE B.NO = 1000;
IF V_CHK > 0 THEN
UPDATE BOARDTBL SET TITLE=V_TITLE, CONTENT=V_CONTENT,
WRITER=V_WRITER WHERE NO=V_NO;
V_RET := 1;
ELSE
INSERT INTO BOARDTBL(NO, TITLE, WRITER, HIT, REGDATE, CONTENT)
VALUES (SEQ_BOARDTBL_NO.NEXTVAL, V_TITLE, V_WRITER, 1, CURRENT_DATE, V_CONTENT);
V_RET := 2;
END IF;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
V_RET := 0;
ROLLBACK;
END;
/
SELECT B.* FROM BOARDTBL B;
DECLARE
V_RET NUMBER;
BEGIN
PROC_BOARD_UPSERT(100, 'PROC제목', 'PROC내용', 'PROC작성자', V_RET);
DBMS_OUTPUT.PUT_LINE('OUT변수 값은 =>' || V_RET);
END;
/
EXEC PROC_BOARD_UPSERT(15, 'PROC제목', 'PROC내용', 'PROC작성자');
'oracle' 카테고리의 다른 글
55일차 xml로 작성해보기 results로 대소문자변경(CLOB포함) (0) | 2022.09.14 |
---|---|
54일차 insert all(seq문제), 트리거(프로시저), vscode에서 일괄 등록 (2) | 2022.09.13 |
50, 51일차 oracle 연결, 테이블, 그룹, 페이지 네이션 (0) | 2022.09.07 |