### : 목차 구분 기호
--- : 목차 내에 항목 구분 기호
목차
1. 이론 및 정보
2. 설정 및 그 밖에
3. 소스코드 또는 실습
4. 과제
###################################
1. 이론 및 정보
-----------------------------------
--- : 목차 내에 항목 구분 기호
목차
1. 이론 및 정보
2. 설정 및 그 밖에
3. 소스코드 또는 실습
4. 과제
###################################
1. 이론 및 정보
-----------------------------------
***. 다중열
MILLER의 데이터를 수정 : 급여를 1500달러로 바꾸기, 보너스를 300달러로 바꾸기
UPDATE EMP SET SAL = 1500, COMM = 300 WHERE EMPNO = 7934;
UPDATE EMP SET SAL = 1500, COMM = 300 WHERE ENAME = 'MILLER';
SELECT ENAME, SAL, COMM, EMPNO FROM EMP WHERE EMPNO =7934;
ENAME SAL COMM EMPNO
---------- ---------- ---------- ----------
MILLER 1300 7934
---------- ---------- ---------- ----------
MILLER 1300 7934
30번 부서의 직원들에 대해서 사번,이름,급여,보너스를 조회
SELECT EMPNO,ENAME,SAL,COMM FROM EMP WHERE DEPTNO = 30;
EMPNO ENAME SAL COMM
---------- ---------- ---------- ----------
7499 ALLEN 1600 300
7521 WARD 1250 500
7654 MARTIN 1250 1400
7698 BLAKE 2850
7844 TURNER 1500 0
7900 JAMES 950
---------- ---------- ---------- ----------
7499 ALLEN 1600 300
7521 WARD 1250 500
7654 MARTIN 1250 1400
7698 BLAKE 2850
7844 TURNER 1500 0
7900 JAMES 950
급여와 보너스가 30번 부서에 있는 직원의 급여와 보너스가 같은 직원에 대해
사번,이름,부서이름,급여,보너스를 조회
다른 부서에도 있는지 체크하는 문제임, 결론은 없음
SELECT EMPNO,ENAME,DEPTNO,SAL,COMM
FROM EMP
WHERE SAL IN (SELECT SAL FROM EMP WHERE DEPTNO = 30)
AND
COMM IN (SELECT COMM FROM EMP WHERE DEPTNO = 30);
EMPNO ENAME DEPTNO SAL COMM
---------- ---------- ---------- ---------- ----------
7499 ALLEN 30 1600 300
7654 MARTIN 30 1250 1400
7521 WARD 30 1250 500
7844 TURNER 30 1500 0
7934 MILLER 10 1500 300
---------- ---------- ---------- ---------- ----------
7499 ALLEN 30 1600 300
7654 MARTIN 30 1250 1400
7521 WARD 30 1250 500
7844 TURNER 30 1500 0
7934 MILLER 10 1500 300
급여와 보너스를 하나씩 비교하니까 MILLER가 꼈음
급여와 보너스를 한꺼번에 비교를 하면 같은 부서의 본인들만 나와야 하는데
MILLER가 껴 있음
이를 가능하게 해주는 다중열임
SELECT EMPNO,ENAME,DEPTNO,SAL,COMM FROM EMP
WHERE (SAL,COMM) IN (SELECT SAL,COMM FROM EMP WHERE DEPTNO = 30);
EMPNO ENAME DEPTNO SAL COMM
---------- ---------- ---------- ---------- ----------
7499 ALLEN 30 1600 300
7521 WARD 30 1250 500
7654 MARTIN 30 1250 1400
7844 TURNER 30 1500 0
---------- ---------- ---------- ---------- ----------
7499 ALLEN 30 1600 300
7521 WARD 30 1250 500
7654 MARTIN 30 1250 1400
7844 TURNER 30 1500 0
-----------------------------------
exists
이를 사용하면 상관서브쿼리가 된다
상관서브쿼리는 부하가 많이 생긴다
-----------------------------------
*. 상관 SUBQUERY
적어도 한명의 직원으로 부터 보고를 받을 수 있는 직원의
이름,업무,입사일자,급여를 조회
-> 부하직원이 한명이라도 있는 사람들
MGR의 사번이 본인인 사람들을 뽑아내라
SELECT ENAME,JOB,HIREDATE,COMM,EMPNO,MGR
FROM EMP
WHERE EMPNO IN (SELECT MGR FROM EMP);
ENAME JOB HIREDATE COMM EMPNO MGR
---------- --------- -------- ---------- ---------- ----------
JONES MANAGER 81/04/02 7566 7839
BLAKE MANAGER 81/05/01 7698 7839
CLARK MANAGER 81/06/09 7782 7839
SCOTT ANALYST 87/04/19 7788 7566
KING PRESIDENT 81/11/17 7839
FORD ANALYST 81/12/03 7902 7566
SELECT ENAME,JOB,HIREDATE,SAL
FROM EMP E
WHERE EXISTS(SELECT * FROM EMP WHERE E.EMPNO = MGR);
FROM EMP E
WHERE EXISTS(SELECT * FROM EMP WHERE E.EMPNO = MGR);
ENAME JOB HIREDATE SAL
---------- --------- -------- ----------
JONES MANAGER 81/04/02 2975
BLAKE MANAGER 81/05/01 2850
CLARK MANAGER 81/06/09 2450
SCOTT ANALYST 87/04/19 3000
KING PRESIDENT 81/11/17 5000
FORD ANALYST 81/12/03 3000
JONES MANAGER 81/04/02 2975
BLAKE MANAGER 81/05/01 2850
CLARK MANAGER 81/06/09 2450
SCOTT ANALYST 87/04/19 3000
KING PRESIDENT 81/11/17 5000
FORD ANALYST 81/12/03 3000
SELECT * FROM EMP WHERE E.EMPNO = MGR;
가능하면 이런 쿼리를 쓰는게 아님
우선 E.으로 테이블 별명을 사용하고 있음
그리고 상관서브쿼리가 되기때문에 부하가 심해지고
시간이 오래걸림
-----------------------------------
***. JOIN
1. 여러개의 테이블을 병합하여 하나의 결과를 도출하기 위한 방법
2. 종류
1) Cartesian Product(join)
- 데카르트 곱
2) Equi Join
- 공통필드의 레코드를 가져오는 방법(중복)
- Inner Join(Natural Join) - 중복 제거
3) Non Equi Join
- 공통된 필드가 없는 경우에 사용
4) Outer Join
- Inner Join의 확장(Inner Join + 공통되지 않은 레코드도 가져옴)
- 종류
left outer join
5) Self Join
- 서로 같은 테이블을 조인
--- 샘플 테이블 작성
CREATE TABLE TBLA(
ID NUMBER,
VALUE NUMBER
);
CREATE TABLE TBLB(
ID NUMBER,
VALUE NUMBER
);
CREATE TABLE TBLC(
ID NUMBER,
VALUE NUMBER
);
INSERT INTO TBLA VALUES(1,10);
INSERT INTO TBLA VALUES(2,20);
INSERT INTO TBLA VALUES(3,30);
INSERT INTO TBLA VALUES(5,50);
INSERT INTO TBLA VALUES(7,70);
INSERT INTO TBLB VALUES(1,10);
INSERT INTO TBLB VALUES(2,20);
INSERT INTO TBLB VALUES(4,40);
INSERT INTO TBLB VALUES(5,50);
INSERT INTO TBLB VALUES(8,80);
INSERT INTO TBLC VALUES(1,10);
INSERT INTO TBLC VALUES(2,20);
INSERT INTO TBLC VALUES(7,70);
INSERT INTO TBLC VALUES(8,80);
INSERT INTO TBLC VALUES(9,90);
3. INNER JOIN
ANSI SQL
JOIN에서 조건문은 ON을 사용
서로 다른 테이블을 조인하는데 필드명이 같은 부분이
있을 수 있음 이를 명확히 어떤 테이블의 필드인지 적어주어야함
SELECT TBLA.ID,TBLA.VALUE FROM TBLA INNER JOIN TBLB ON TBLA.ID = TBLB.ID;
ID VALUE
---------- ----------
1 10
2 20
5 50
1 10
2 20
5 50
SELECT TBLA.ID,TBLA.VALUE FROM TBLA JOIN TBLB ON TBLA.ID = TBLB.ID;
INNER 없어도 디폴트로 INNER JOIN임
PL/SQL
SELECT TBLA.ID,TBLA.VALUE FROM TBLA,TBLB WHERE TBLA.ID = TBLB.ID;
직원의 사번,이름,업무,부서번호,부서명을 조회
SELECT EMPNO,ENAME,JOB,EMP.DEPTNO,DNAME
FROM EMP INNER JOIN DEPT
ON EMP.DEPTNO = DEPT.DEPTNO;
EMPNO ENAME JOB DEPTNO DNAME
---------- ---------- --------- ---------- --------------
7782 CLARK MANAGER 10 ACCOUNTING
7839 KING PRESIDENT 10 ACCOUNTING
7934 MILLER CLERK 10 ACCOUNTING
7566 JONES MANAGER 20 RESEARCH
7902 FORD ANALYST 20 RESEARCH
7876 ADAMS CLERK 20 RESEARCH
7369 SMITH CLERK 20 RESEARCH
7788 SCOTT ANALYST 20 RESEARCH
7521 WARD SALESMAN 30 SALES
7844 TURNER SALESMAN 30 SALES
7499 ALLEN SALESMAN 30 SALES
7900 JAMES CLERK 30 SALES
7698 BLAKE MANAGER 30 SALES
7654 MARTIN SALESMAN 30 SALES
---------- ---------- --------- ---------- --------------
7782 CLARK MANAGER 10 ACCOUNTING
7839 KING PRESIDENT 10 ACCOUNTING
7934 MILLER CLERK 10 ACCOUNTING
7566 JONES MANAGER 20 RESEARCH
7902 FORD ANALYST 20 RESEARCH
7876 ADAMS CLERK 20 RESEARCH
7369 SMITH CLERK 20 RESEARCH
7788 SCOTT ANALYST 20 RESEARCH
7521 WARD SALESMAN 30 SALES
7844 TURNER SALESMAN 30 SALES
7499 ALLEN SALESMAN 30 SALES
7900 JAMES CLERK 30 SALES
7698 BLAKE MANAGER 30 SALES
7654 MARTIN SALESMAN 30 SALES
SALESMAN에 대해서 사번,이름,업무,부서번호,부서명을 조회
SELECT EMPNO,ENAME,JOB,EMP.DEPTNO,DNAME FROM EMP INNER JOIN DEPT
ON EMP.DEPTNO = DEPT.DEPTNO AND JOB = 'SALESMAN';
SELECT EMPNO,ENAME,JOB,EMP.DEPTNO,DNAME FROM EMP INNER JOIN DEPT
ON EMP.DEPTNO = DEPT.DEPTNO
WHERE JOB = 'SALESMAN';
EMPNO ENAME JOB DEPTNO DNAME
---------- ---------- --------- ---------- --------------
7499 ALLEN SALESMAN 30 SALES
7844 TURNER SALESMAN 30 SALES
7654 MARTIN SALESMAN 30 SALES
7521 WARD SALESMAN 30 SALES
---------- ---------- --------- ---------- --------------
7499 ALLEN SALESMAN 30 SALES
7844 TURNER SALESMAN 30 SALES
7654 MARTIN SALESMAN 30 SALES
7521 WARD SALESMAN 30 SALES
테이블에 별명을 줄 수 있음
그러나 별명을 주면 무줘건 별명만으로 사용해야 한다
SELECT TBLA.ID, TBLA.VALUE FROM TBLA A INNER JOIN TBLB B ON A.ID = B.ID;SELECT A.ID,A.VALUE FROM TBLA A INNER JOIN TBLB B ON A.ID = B.ID;
SELECT TBLA.ID, TBLA.VALUE FROM TBLA,TBLB; --CARTESIAN PRODUCT 결과가 나온다.
특별한 경우에만 쓰이고 보통 실수에 의해서 쿼리문을 작성하게 됨
4. OUTER JOIN
SELECT A.ID, A.VALUE
FROM TBLA A INNER JOIN TBLB B
ON A.ID = B.ID;
ID VALUE
---------- ----------
1 10
2 20
5 50
---------- ----------
1 10
2 20
5 50
SELECT A.ID, A.VALUE
FROM TBLA A LEFT OUTER JOIN TBLB B
ON A.ID = B.ID;
ID VALUE
---------- ----------
1 10
2 20
5 50
7 70
3 30
---------- ----------
1 10
2 20
5 50
7 70
3 30
SELECT A.ID, A.VALUE, B.ID, B.VALUE
FROM TBLA A RIGHT OUTER JOIN TBLB B
ON A.ID = B.ID;
ID VALUE ID VALUE
---------- ---------- ---------- ----------
1 10 1 10
2 20 2 20
5 50 5 50
4 40
8 80
---------- ---------- ---------- ----------
1 10 1 10
2 20 2 20
5 50 5 50
4 40
8 80
SELECT A.ID, A.VALUE, B.ID, B.VALUE
FROM TBLA A FULL OUTER JOIN TBLB B
ON A.ID = B.ID;
ID VALUE ID VALUE
---------- ---------- ---------- ----------
1 10 1 10
2 20 2 20
4 40
5 50 5 50
8 80
7 70
3 30
---------- ---------- ---------- ----------
1 10 1 10
2 20 2 20
4 40
5 50 5 50
8 80
7 70
3 30
PL/SQL
LEFT OUTER JOIN
SELECT A.ID, A.VALUE, B.ID, B.VALUE
FROM TBLA A,TBLB B
WHERE A.ID = B.ID(+);
RIGHT OUTER JOIN
SELECT A.ID, A.VALUE, B.ID, B.VALUE
FROM TBLA A,TBLB B
WHERE A.ID(+) = B.ID;
FULL OUTER JOIN은 표준에서만 지원함
이름,급여,부서명,근무지를 조회하시오.
단 부서명과 근무지는 모두 출력할수 있도록 하시오.
아래 출력결과를 보면 OPERATIONS BOSTON도 있음
SELECT * FROM DEPT;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
SELECT ENAME,SAL,DEPT.DNAME,LOC
FROM EMP RIGHT OUTER JOIN DEPT
ON EMP.DEPTNO = DEPT.DEPTNO;
ENAME SAL DNAME LOC
---------- ---------- -------------- -------------
CLARK 2450 ACCOUNTING NEW YORK
KING 5000 ACCOUNTING NEW YORK
MILLER 1500 ACCOUNTING NEW YORK
JONES 2975 RESEARCH DALLAS
FORD 3000 RESEARCH DALLAS
ADAMS 1100 RESEARCH DALLAS
SMITH 800 RESEARCH DALLAS
SCOTT 3000 RESEARCH DALLAS
WARD 1250 SALES CHICAGO
TURNER 1500 SALES CHICAGO
ALLEN 1600 SALES CHICAGO
JAMES 950 SALES CHICAGO
BLAKE 2850 SALES CHICAGO
MARTIN 1250 SALES CHICAGO
OPERATIONS BOSTON
---------- ---------- -------------- -------------
CLARK 2450 ACCOUNTING NEW YORK
KING 5000 ACCOUNTING NEW YORK
MILLER 1500 ACCOUNTING NEW YORK
JONES 2975 RESEARCH DALLAS
FORD 3000 RESEARCH DALLAS
ADAMS 1100 RESEARCH DALLAS
SMITH 800 RESEARCH DALLAS
SCOTT 3000 RESEARCH DALLAS
WARD 1250 SALES CHICAGO
TURNER 1500 SALES CHICAGO
ALLEN 1600 SALES CHICAGO
JAMES 950 SALES CHICAGO
BLAKE 2850 SALES CHICAGO
MARTIN 1250 SALES CHICAGO
OPERATIONS BOSTON
세개의 테이블 조인
SELECT A.ID, A.VALUE
FROM TBLA A INNER JOIN TBLB B
ON A.ID = B.ID
INNER JOIN TBLC C
ON B.ID = C.ID;
ID VALUE
---------- ----------
1 10
2 20
---------- ----------
1 10
2 20
PL/SQL
SELECT A.ID, A.VALUE
FROM TBLA A,TBLB B,TBLC C
WHERE A.ID = B.ID AND B.ID = C.ID;
5. NON EQUI JOIN
SELECT * FROM SALGRADE;
GRADE LOSAL HISAL
---------- ---------- ----------
1 700 1200
2 1201 1400
3 1401 2000
4 2001 3000
5 3001 9999
1 700 1200
2 1201 1400
3 1401 2000
4 2001 3000
5 3001 9999
직원의 사번,이름,급여,급여등급을 조회 - 공통필드가 없음
SELECT EMPNO,ENAME,SAL,GRADE,LOSAL,HISAL
FROM EMP INNER JOIN SALGRADE
ON SAL >= LOSAL AND SAL <= HISAL;
------ ---------- ---------- ---------- ---------- ----------
7369 SMITH 800 1 700 1200
7900 JAMES 950 1 700 1200
7876 ADAMS 1100 1 700 1200
7521 WARD 1250 2 1201 1400
7654 MARTIN 1250 2 1201 1400
7934 MILLER 1500 3 1401 2000
7844 TURNER 1500 3 1401 2000
7499 ALLEN 1600 3 1401 2000
7782 CLARK 2450 4 2001 3000
7698 BLAKE 2850 4 2001 3000
7566 JONES 2975 4 2001 3000
7788 SCOTT 3000 4 2001 3000
7902 FORD 3000 4 2001 3000
7839 KING 5000 5 3001 9999
6. SELF JOIN - 반드시 별명을 적어야함
직원의 사번,이름,업무,관리자,관리자이름 출력
SELECT E.EMPNO,E.ENAME,E.JOB,E.MGR,
X.ENAME "관리자이름",X.EMPNO "관리자EMPNO"
FROM EMP E INNER JOIN EMP X
ON E.MGR = X.EMPNO;
EMPNO ENAME JOB MGR 관리자이름 관리자EMPNO
------ ---------- --------- ---------- ---------- -----------
7902 FORD ANALYST 7566 JONES 7566
7788 SCOTT ANALYST 7566 JONES 7566
7844 TURNER SALESMAN 7698 BLAKE 7698
7499 ALLEN SALESMAN 7698 BLAKE 7698
7521 WARD SALESMAN 7698 BLAKE 7698
7900 JAMES CLERK 7698 BLAKE 7698
7654 MARTIN SALESMAN 7698 BLAKE 7698
7934 MILLER CLERK 7782 CLARK 7782
7876 ADAMS CLERK 7788 SCOTT 7788
7698 BLAKE MANAGER 7839 KING 7839
7566 JONES MANAGER 7839 KING 7839
7782 CLARK MANAGER 7839 KING 7839
7369 SMITH CLERK 7902 FORD 7902
------ ---------- --------- ---------- ---------- -----------
7902 FORD ANALYST 7566 JONES 7566
7788 SCOTT ANALYST 7566 JONES 7566
7844 TURNER SALESMAN 7698 BLAKE 7698
7499 ALLEN SALESMAN 7698 BLAKE 7698
7521 WARD SALESMAN 7698 BLAKE 7698
7900 JAMES CLERK 7698 BLAKE 7698
7654 MARTIN SALESMAN 7698 BLAKE 7698
7934 MILLER CLERK 7782 CLARK 7782
7876 ADAMS CLERK 7788 SCOTT 7788
7698 BLAKE MANAGER 7839 KING 7839
7566 JONES MANAGER 7839 KING 7839
7782 CLARK MANAGER 7839 KING 7839
7369 SMITH CLERK 7902 FORD 7902
-----------------------------------
SQL 표준문법
ANSI SQL 이 표준 문법임
제품별 SQL이 있음
ORACLE - PL/SQL
MSSQL - T/SQL
-----------------------------------
***. SET OPERATOR - 테이블 교집합, 차집합과 비슷한 개념
1. 종류
1) UNION - 합집합 중복 제거
2) UNION ALL - 합집합 중복 포함
3) INTERSECT - 교집합
4) MINUS - 차집합
JOIN과 SET 연산자는 결과는 똑같은데 방법이 다름
JOIN은 먼저 합친 다음에 결과를 가져옴
SET 연산자는 각각 컴파일을 하고 결과값을 나중에 합침
SELECT DEPTNO FROM DEPT;
DEPTNO
-------
10
20
30
40
-------
10
20
30
40
SELECT DEPTNO FROM EMP;
DEPTNO
-------
20
30
30
20
30
30
10
20
10
30
20
30
20
10
-------
20
30
30
20
30
30
10
20
10
30
20
30
20
10
SELECT DEPTNO FROM DEPT
UNION
SELECT DEPTNO FROM EMP;
DEPTNO
-------
10
20
30
40
-------
10
20
30
40
SELECT DEPTNO FROM DEPT
UNION ALL
SELECT DEPTNO FROM EMP;
DEPTNO
-------
10
20
30
40
20
30
30
20
30
30
10
20
10
30
20
30
20
10
-------
10
20
30
40
20
30
30
20
30
30
10
20
10
30
20
30
20
10
SELECT DEPTNO FROM DEPT
INTERSECT
SELECT DEPTNO FROM EMP;
DEPTNO
-------
10
20
30
-------
10
20
30
SELECT DEPTNO FROM DEPT
MINUS
SELECT DEPTNO FROM EMP;
DEPTNO
-------
40
-------
40
-----------------------------------
-----------------------------------
-----------------------------------
###################################
2. 설정 및 그 밖에
-----------------------------------
한권의 책에 대해 두명 이상의 작가가 쓴 책을 검색하시오
책이름 작가명 작가명
9. 한권의 책에 대해 세명의 작가가 쓴 책을 검색하시오
책이름 작가명 작가명 작가명
2. 설정 및 그 밖에
-----------------------------------
-----------------------------------
-----------------------------------
-----------------------------------
###################################
3. 소스코드 또는 실습
-----------------------------------
###################################
3. 소스코드 또는 실습
-----------------------------------
-----------------------------------
###################################
4. 과제
-----------------------------------
###################################
4. 과제
-----------------------------------
문제1 - 서브쿼리로만 푸시오
1. BLAKE와 같은 부서에 있는 모든 직원의 사번,이름,입사일자 조회
2. SELECT EMPNO,ENAME,DEPTNO,SAL,COMM FROM EMP
WHERE (SAL,COMM) IN (SELECT SAL,COMM FROM EMP WHERE DEPTNO = 30);
이 쿼리문을 수정하여 보너스가 NULL인 직원도 출력
3. 평균급여 이상을 받는 직원들의 사번, 이름을 조회
단. 급여가 많은 순으로 정렬
4. 이름에 T자가 들어가는 직원이 근무하는 부서에서
근무하는 직원의 사번,이름,급여조회
5. 부서의 위치가 DALLAS인 모든 직원에 대해 사번,이름,급여,업무를 조회
6. KING에게 보고하는 모든 직원의 이름과 부서,업무,급여를 조회
7. 월급이 30번 부서의 최저 급여보다 높은 직원의 사번,이름,급여를 조회
8. 10번부서에서 30번부서의 직원과 같은 업무를 하는 직원의 이름과 업무를 조회
-----------------------------------
문제2 - JOIN
1. NEWYORK에서 근무하는 직원의 사번,이름,업무,부서명을 조회
2. 이름,급여,부서명,근무지를 조회하시오.
단, 부서명과 근무지는 모두 출력할 수 있도록 하시오.
3. COMM을 받는 직원에 대해 이름,부서명,근무지를 조회
4. 이름 중간에 L자가 있는 직원에 대해 이름,업무,부서명,근무지 조회
5. 각 직원들에 대해서 그들의 관리자보다 먼저 입사한 직원에 대해
이름,입사일,관리자이름,관리자 입사일을 조회
6. 말단사원의 사번,이름,업무,부서번호,근무지를 조회
7. 근무지가 DALLAS인 직원의 사번,이름,급여,급여등급을 조회
8.
CREATE TABLE TBLBOOK(
AUTHOR VARCHAR2(15),
TITLE VARCHAR2(15)
);
INSERT INTO TBLBOOK VALUES('최주현', '하늘과 땅');
INSERT INTO TBLBOOK VALUES('최주현', '바다');
INSERT INTO TBLBOOK VALUES('유은정', '바다');
INSERT INTO TBLBOOK VALUES('박성우', '문');
INSERT INTO TBLBOOK VALUES('최주현', '문');
INSERT INTO TBLBOOK VALUES('박성우', '천국');
INSERT INTO TBLBOOK VALUES('최지은', '천국');
INSERT INTO TBLBOOK VALUES('최주현', '천국');
INSERT INTO TBLBOOK VALUES('박성우', '고슴도치');
INSERT INTO TBLBOOK VALUES('서금동', '나');
CREATE TABLE TBLBOOK(
AUTHOR VARCHAR2(15),
TITLE VARCHAR2(15)
);
INSERT INTO TBLBOOK VALUES('최주현', '하늘과 땅');
INSERT INTO TBLBOOK VALUES('최주현', '바다');
INSERT INTO TBLBOOK VALUES('유은정', '바다');
INSERT INTO TBLBOOK VALUES('박성우', '문');
INSERT INTO TBLBOOK VALUES('최주현', '문');
INSERT INTO TBLBOOK VALUES('박성우', '천국');
INSERT INTO TBLBOOK VALUES('최지은', '천국');
INSERT INTO TBLBOOK VALUES('최주현', '천국');
INSERT INTO TBLBOOK VALUES('박성우', '고슴도치');
INSERT INTO TBLBOOK VALUES('서금동', '나');
한권의 책에 대해 두명 이상의 작가가 쓴 책을 검색하시오
책이름 작가명 작가명
9. 한권의 책에 대해 세명의 작가가 쓴 책을 검색하시오
책이름 작가명 작가명 작가명
-----------------------------------
프로젝트에 관한 간단한 설명서 만들기
###################################
5. 과제 해결
-----------------------------------
5. 과제 해결
-----------------------------------
4. 과제
-----------------------------------
4. 과제
-----------------------------------
문제1 - 서브쿼리로만 푸시오
1. BLAKE와 같은 부서에 있는 모든 직원의 사번,이름,입사일자 조회
SELECT EMPNO,ENAME,HIREDATE,DEPTNO
FROM EMP
WHERE DEPTNO = (SELECT DEPTNO FROM EMP WHERE ENAME = 'BLAKE');
EMPNO ENAME HIREDATE DEPTNO
------ ---------- -------- ----------
7499 ALLEN 81/02/20 30
7521 WARD 81/02/22 30
7654 MARTIN 81/09/28 30
7698 BLAKE 81/05/01 30
7844 TURNER 81/09/08 30
7900 JAMES 81/12/03 30
확인 방법
SELECT DEPTNO FROM EMP WHERE ENAME = 'BLAKE'
DEPTNO
-------
30
SELECT EMPNO,ENAME,HIREDATE,DEPTNO
FROM EMP
WHERE DEPTNO = 30;
2.
과제 하기 전에 아래 쿼리문이 있어야함
UPDATE EMP SET SAL = 1500, COMM = 300 WHERE ENAME = 'MILLER';
SELECT EMPNO,ENAME,DEPTNO,SAL,COMM FROM EMP
WHERE (SAL,COMM) IN (SELECT SAL,COMM FROM EMP WHERE DEPTNO = 30);
이 쿼리문을 수정하여 보너스가 NULL인 직원도 출력
SELECT EMPNO,ENAME,DEPTNO,SAL,COMM FROM EMP
WHERE (SAL,NVL(COMM,0)) IN (SELECT SAL,NVL(COMM,0)
FROM EMP WHERE DEPTNO = 30);
EMPNO ENAME DEPTNO SAL COMM
------ ---------- ---------- ---------- ----------
7499 ALLEN 30 1600 300
7521 WARD 30 1250 500
7654 MARTIN 30 1250 1400
7698 BLAKE 30 2850
7844 TURNER 30 1500 0
7900 JAMES 30 950
3. 평균급여 이상을 받는 직원들의 사번, 이름을 조회
단. 급여가 많은 순으로 정렬
SELECT EMPNO,ENAME,SAL
FROM EMP
WHERE SAL > (SELECT AVG(SAL) FROM EMP)
ORDER BY SAL DESC;
AVG(SAL)
--------
2087.5
EMPNO ENAME SAL
------- ---------- ----------
7839 KING 5000
7902 FORD 3000
7788 SCOTT 3000
7566 JONES 2975
7698 BLAKE 2850
7782 CLARK 2450
4. 이름에 T자가 들어가는 직원이 근무하는 부서에서
근무하는 직원의 사번,이름,급여조회
SELECT EMPNO,ENAME,SAL FROM EMP
WHERE INSTR(ENAME,'T') > 0;
SELECT EMPNO,ENAME,SAL FROM EMP WHERE DEPTNO
IN (SELECT DEPTNO FROM EMP WHERE ENAME LIKE '%T%');
SELECT EMPNO,ENAME,SAL FROM EMP WHERE DEPTNO
IN (SELECT DEPTNO FROM EMP WHERE INSTR(ENAME,'T') > 0);
EMPNO ENAME SAL
------ ---------- ----------
7902 FORD 3000
7876 ADAMS 1100
7788 SCOTT 3000
7566 JONES 2975
7369 SMITH 800
7900 JAMES 950
7844 TURNER 1500
7698 BLAKE 2850
7654 MARTIN 1250
7521 WARD 1250
7499 ALLEN 1600
5. 부서의 위치가 DALLAS인 모든 직원에 대해 사번,이름,급여,업무를 조회
SELECT EMPNO,ENAME,SAL,JOB
FROM EMP
WHERE DEPTNO = (SELECT DEPTNO FROM DEPT WHERE LOC = 'DALLAS');
EMPNO ENAME SAL JOB
------ ---------- ---------- -------
7369 SMITH 800 CLERK
7566 JONES 2975 MANAGER
7788 SCOTT 3000 ANALYST
7876 ADAMS 1100 CLERK
7902 FORD 3000 ANALYST
6. KING에게 보고하는 모든 직원의 이름과 부서,업무,급여를 조회
SELECT ENAME,DEPTNO,JOB,SAL
FROM EMP
WHERE MGR = (SELECT EMPNO FROM EMP WHERE ENAME = 'KING');
ENAME DEPTNO JOB SAL
---------- ---------- --------- ----------
JONES 20 MANAGER 2975
BLAKE 30 MANAGER 2850
CLARK 10 MANAGER 2450
7. 월급이 30번 부서의 최저 급여보다 높은 직원의 사번,이름,급여를 조회
SELECT EMPNO,ENAME,SAL FROM EMP
WHERE SAL > (SELECT MIN(SAL) FROM EMP WHERE DEPTNO = 30);
EMPNO ENAME SAL
------ ---------- ----------
7499 ALLEN 1600
7521 WARD 1250
7566 JONES 2975
7654 MARTIN 1250
7698 BLAKE 2850
7782 CLARK 2450
7788 SCOTT 3000
7839 KING 5000
7844 TURNER 1500
7876 ADAMS 1100
7902 FORD 3000
7934 MILLER 1500
MIN(SAL)
---------
950
8. 10번부서에서 30번부서의 직원과 같은 업무를 하는 직원의 이름과 업무를 조회
SELECT ENAME, JOB FROM EMP
WHERE DEPTNO = 30 AND JOB IN (SELECT JOB FROM EMP WHERE DEPTNO = 10);
ENAME JOB
---------- -------
BLAKE MANAGER
JAMES CLERK
SELECT ENAME,JOB FROM EMP WHERE DEPTNO = 30;
SELECT ENAME,JOB FROM EMP WHERE DEPTNO = 10;
-----------------------------------
문제2 - JOIN
1. NEWYORK에서 근무하는 직원의 사번,이름,업무,부서명을 조회
SELECT EMPNO,ENAME,JOB,EMP.DEPTNO
FROM EMP INNER JOIN DEPT
ON EMP.DEPTNO = DEPT.DEPTNO
AND DEPT.LOC = 'NEW YORK';
EMPNO ENAME JOB DEPTNO
------ ---------- --------- ----------
7782 CLARK MANAGER 10
7839 KING PRESIDENT 10
7934 MILLER CLERK 10
2. 이름,급여,부서명,근무지를 조회하시오.
단, 부서명과 근무지는 모두 출력할 수 있도록 하시오.
SELECT ENAME,SAL,D.DNAME,D.LOC
FROM EMP E RIGHT OUTER JOIN DEPT D
ON E.DEPTNO = D.DEPTNO;
ENAME SAL DNAME LOC
---------- ---------- -------------- --------
CLARK 2450 ACCOUNTING NEW YORK
KING 5000 ACCOUNTING NEW YORK
MILLER 1500 ACCOUNTING NEW YORK
JONES 2975 RESEARCH DALLAS
FORD 3000 RESEARCH DALLAS
ADAMS 1100 RESEARCH DALLAS
SMITH 800 RESEARCH DALLAS
SCOTT 3000 RESEARCH DALLAS
WARD 1250 SALES CHICAGO
TURNER 1500 SALES CHICAGO
ALLEN 1600 SALES CHICAGO
JAMES 950 SALES CHICAGO
BLAKE 2850 SALES CHICAGO
MARTIN 1250 SALES CHICAGO
OPERATIONS BOSTON
3. COMM을 받는 직원에 대해 이름,부서명,근무지를 조회
SELECT ENAME,E.DEPTNO,D.LOC,E.COMM
FROM EMP E INNER JOIN DEPT D
ON E.DEPTNO = D.DEPTNO
WHERE COMM IS NOT NULL;
ENAME DEPTNO LOC COMM
---------- ---------- ------------- ----------
MILLER 10 NEW YORK 300
WARD 30 CHICAGO 500
TURNER 30 CHICAGO 0
ALLEN 30 CHICAGO 300
MARTIN 30 CHICAGO 1400
4. 이름 중간에 L자가 있는 직원에 대해 이름,업무,부서명,근무지 조회
SELECT ENAME,E.DEPTNO,D.LOC
FROM EMP E INNER JOIN DEPT D
ON E.DEPTNO = D.DEPTNO
WHERE INSTR(ENAME,'L') > 0;
ENAME DEPTNO LOC
---------- ---------- --------
ALLEN 30 CHICAGO
BLAKE 30 CHICAGO
CLARK 10 NEW YORK
MILLER 10 NEW YORK
5. 각 직원들에 대해서 그들의 관리자보다 먼저 입사한 직원에 대해
이름,입사일,관리자이름,관리자 입사일을 조회
SELECT E.ENAME,E.HIREDATE,E.MGR,X.ENAME,X.HIREDATE,X.EMPNO
FROM EMP E INNER JOIN EMP X
ON E.MGR = X.EMPNO
WHERE E.HIREDATE < X.HIREDATE;
ENAME HIREDATE MGR ENAME HIREDATE EMPNO
---------- -------- ---------- ---------- -------- ----------
ALLEN 81/02/20 7698 BLAKE 81/05/01 7698
WARD 81/02/22 7698 BLAKE 81/05/01 7698
BLAKE 81/05/01 7839 KING 81/11/17 7839
JONES 81/04/02 7839 KING 81/11/17 7839
CLARK 81/06/09 7839 KING 81/11/17 7839
SMITH 80/12/17 7902 FORD 81/12/03 7902
6. 말단사원의 사번,이름,업무,부서번호,근무지를 조회
SELECT E.EMPNO,E.ENAME,E.JOB,E.DEPTNO,D.LOC
FROM EMP E INNER JOIN DEPT D
ON E.DEPTNO = D.DEPTNO
WHERE NOT EXISTS (SELECT EMPNO FROM EMP WHERE E.EMPNO = MGR);
SELECT E.EMPNO,E.ENAME,E.JOB,E.DEPTNO,D.LOC
FROM EMP E INNER JOIN DEPT D
ON E.DEPTNO = D.DEPTNO
WHERE EXISTS (SELECT EMPNO FROM EMP WHERE E.EMPNO <> MGR);
EMPNO ENAME JOB DEPTNO LOC
------ ---------- --------- ---------- --------
7844 TURNER SALESMAN 30 CHICAGO
7521 WARD SALESMAN 30 CHICAGO
7654 MARTIN SALESMAN 30 CHICAGO
7499 ALLEN SALESMAN 30 CHICAGO
7934 MILLER CLERK 10 NEW YORK
7369 SMITH CLERK 20 DALLAS
7876 ADAMS CLERK 20 DALLAS
7900 JAMES CLERK 30 CHICAGO
7. 근무지가 DALLAS인 직원의 사번,이름,급여,급여등급을 조회
SELECT E.EMPNO,E.ENAME,E.SAL,E.DEPTNO,S.GRADE,D.LOC
FROM EMP E INNER JOIN DEPT D
ON E.DEPTNO = D.DEPTNO
INNER JOIN SALGRADE S
ON D.LOC = 'DALLAS'
WHERE E.SAL BETWEEN S.LOSAL AND S.HISAL;
EMPNO ENAME SAL DEPTNO GRADE LOC
------ ---------- ---------- ---------- ---------- ------
7369 SMITH 800 20 1 DALLAS
7876 ADAMS 1100 20 1 DALLAS
7566 JONES 2975 20 4 DALLAS
7788 SCOTT 3000 20 4 DALLAS
7902 FORD 3000 20 4 DALLAS
8.
CREATE TABLE TBLBOOK(
AUTHOR VARCHAR2(15),
TITLE VARCHAR2(15)
);
INSERT INTO TBLBOOK VALUES('최주현', '하늘과 땅');
INSERT INTO TBLBOOK VALUES('최주현', '바다');
INSERT INTO TBLBOOK VALUES('유은정', '바다');
INSERT INTO TBLBOOK VALUES('박성우', '문');
INSERT INTO TBLBOOK VALUES('최주현', '문');
INSERT INTO TBLBOOK VALUES('박성우', '천국');
INSERT INTO TBLBOOK VALUES('최지은', '천국');
INSERT INTO TBLBOOK VALUES('최주현', '천국');
INSERT INTO TBLBOOK VALUES('박성우', '고슴도치');
INSERT INTO TBLBOOK VALUES('서금동', '나');
한권의 책에 대해 두명 이상의 작가가 쓴 책을 검색하시오
책이름 작가명 작가명
SELECT A.TITLE,A.AUTHOR,B.AUTHOR
FROM TBLBOOK A INNER JOIN TBLBOOK B
ON A.TITLE = B.TITLE
AND A.AUTHOR < B.AUTHOR;
TITLE AUTHOR AUTHOR
--------------- --------------- -------
바다 유은정 최주현
문 박성우 최주현
천국 최주현 최지은
천국 박성우 최지은
천국 박성우 최주현
9. 한권의 책에 대해 세명의 작가가 쓴 책을 검색하시오
책이름 작가명 작가명 작가명
-----------------------------------
4. 과제
-----------------------------------
문제1 - 서브쿼리로만 푸시오
1. BLAKE와 같은 부서에 있는 모든 직원의 사번,이름,입사일자 조회
SELECT EMPNO,ENAME,HIREDATE,DEPTNO
FROM EMP
WHERE DEPTNO = (SELECT DEPTNO FROM EMP WHERE ENAME = 'BLAKE');
EMPNO ENAME HIREDATE DEPTNO
------ ---------- -------- ----------
7499 ALLEN 81/02/20 30
7521 WARD 81/02/22 30
7654 MARTIN 81/09/28 30
7698 BLAKE 81/05/01 30
7844 TURNER 81/09/08 30
7900 JAMES 81/12/03 30
확인 방법
SELECT DEPTNO FROM EMP WHERE ENAME = 'BLAKE'
DEPTNO
-------
30
SELECT EMPNO,ENAME,HIREDATE,DEPTNO
FROM EMP
WHERE DEPTNO = 30;
2.
과제 하기 전에 아래 쿼리문이 있어야함
UPDATE EMP SET SAL = 1500, COMM = 300 WHERE ENAME = 'MILLER';
SELECT EMPNO,ENAME,DEPTNO,SAL,COMM FROM EMP
WHERE (SAL,COMM) IN (SELECT SAL,COMM FROM EMP WHERE DEPTNO = 30);
이 쿼리문을 수정하여 보너스가 NULL인 직원도 출력
SELECT EMPNO,ENAME,DEPTNO,SAL,COMM FROM EMP
WHERE (SAL,NVL(COMM,0)) IN (SELECT SAL,NVL(COMM,0)
FROM EMP WHERE DEPTNO = 30);
EMPNO ENAME DEPTNO SAL COMM
------ ---------- ---------- ---------- ----------
7499 ALLEN 30 1600 300
7521 WARD 30 1250 500
7654 MARTIN 30 1250 1400
7698 BLAKE 30 2850
7844 TURNER 30 1500 0
7900 JAMES 30 950
3. 평균급여 이상을 받는 직원들의 사번, 이름을 조회
단. 급여가 많은 순으로 정렬
SELECT EMPNO,ENAME,SAL
FROM EMP
WHERE SAL > (SELECT AVG(SAL) FROM EMP)
ORDER BY SAL DESC;
AVG(SAL)
--------
2087.5
EMPNO ENAME SAL
------- ---------- ----------
7839 KING 5000
7902 FORD 3000
7788 SCOTT 3000
7566 JONES 2975
7698 BLAKE 2850
7782 CLARK 2450
4. 이름에 T자가 들어가는 직원이 근무하는 부서에서
근무하는 직원의 사번,이름,급여조회
SELECT EMPNO,ENAME,SAL FROM EMP
WHERE INSTR(ENAME,'T') > 0;
SELECT EMPNO,ENAME,SAL FROM EMP WHERE DEPTNO
IN (SELECT DEPTNO FROM EMP WHERE ENAME LIKE '%T%');
SELECT EMPNO,ENAME,SAL FROM EMP WHERE DEPTNO
IN (SELECT DEPTNO FROM EMP WHERE INSTR(ENAME,'T') > 0);
EMPNO ENAME SAL
------ ---------- ----------
7902 FORD 3000
7876 ADAMS 1100
7788 SCOTT 3000
7566 JONES 2975
7369 SMITH 800
7900 JAMES 950
7844 TURNER 1500
7698 BLAKE 2850
7654 MARTIN 1250
7521 WARD 1250
7499 ALLEN 1600
5. 부서의 위치가 DALLAS인 모든 직원에 대해 사번,이름,급여,업무를 조회
SELECT EMPNO,ENAME,SAL,JOB
FROM EMP
WHERE DEPTNO = (SELECT DEPTNO FROM DEPT WHERE LOC = 'DALLAS');
EMPNO ENAME SAL JOB
------ ---------- ---------- -------
7369 SMITH 800 CLERK
7566 JONES 2975 MANAGER
7788 SCOTT 3000 ANALYST
7876 ADAMS 1100 CLERK
7902 FORD 3000 ANALYST
6. KING에게 보고하는 모든 직원의 이름과 부서,업무,급여를 조회
SELECT ENAME,DEPTNO,JOB,SAL
FROM EMP
WHERE MGR = (SELECT EMPNO FROM EMP WHERE ENAME = 'KING');
ENAME DEPTNO JOB SAL
---------- ---------- --------- ----------
JONES 20 MANAGER 2975
BLAKE 30 MANAGER 2850
CLARK 10 MANAGER 2450
7. 월급이 30번 부서의 최저 급여보다 높은 직원의 사번,이름,급여를 조회
SELECT EMPNO,ENAME,SAL FROM EMP
WHERE SAL > (SELECT MIN(SAL) FROM EMP WHERE DEPTNO = 30);
EMPNO ENAME SAL
------ ---------- ----------
7499 ALLEN 1600
7521 WARD 1250
7566 JONES 2975
7654 MARTIN 1250
7698 BLAKE 2850
7782 CLARK 2450
7788 SCOTT 3000
7839 KING 5000
7844 TURNER 1500
7876 ADAMS 1100
7902 FORD 3000
7934 MILLER 1500
MIN(SAL)
---------
950
8. 10번부서에서 30번부서의 직원과 같은 업무를 하는 직원의 이름과 업무를 조회
SELECT ENAME, JOB FROM EMP
WHERE DEPTNO = 30 AND JOB IN (SELECT JOB FROM EMP WHERE DEPTNO = 10);
ENAME JOB
---------- -------
BLAKE MANAGER
JAMES CLERK
SELECT ENAME,JOB FROM EMP WHERE DEPTNO = 30;
SELECT ENAME,JOB FROM EMP WHERE DEPTNO = 10;
-----------------------------------
문제2 - JOIN
1. NEWYORK에서 근무하는 직원의 사번,이름,업무,부서명을 조회
SELECT EMPNO,ENAME,JOB,EMP.DEPTNO
FROM EMP INNER JOIN DEPT
ON EMP.DEPTNO = DEPT.DEPTNO
AND DEPT.LOC = 'NEW YORK';
EMPNO ENAME JOB DEPTNO
------ ---------- --------- ----------
7782 CLARK MANAGER 10
7839 KING PRESIDENT 10
7934 MILLER CLERK 10
2. 이름,급여,부서명,근무지를 조회하시오.
단, 부서명과 근무지는 모두 출력할 수 있도록 하시오.
SELECT ENAME,SAL,D.DNAME,D.LOC
FROM EMP E RIGHT OUTER JOIN DEPT D
ON E.DEPTNO = D.DEPTNO;
ENAME SAL DNAME LOC
---------- ---------- -------------- --------
CLARK 2450 ACCOUNTING NEW YORK
KING 5000 ACCOUNTING NEW YORK
MILLER 1500 ACCOUNTING NEW YORK
JONES 2975 RESEARCH DALLAS
FORD 3000 RESEARCH DALLAS
ADAMS 1100 RESEARCH DALLAS
SMITH 800 RESEARCH DALLAS
SCOTT 3000 RESEARCH DALLAS
WARD 1250 SALES CHICAGO
TURNER 1500 SALES CHICAGO
ALLEN 1600 SALES CHICAGO
JAMES 950 SALES CHICAGO
BLAKE 2850 SALES CHICAGO
MARTIN 1250 SALES CHICAGO
OPERATIONS BOSTON
3. COMM을 받는 직원에 대해 이름,부서명,근무지를 조회
SELECT ENAME,E.DEPTNO,D.LOC,E.COMM
FROM EMP E INNER JOIN DEPT D
ON E.DEPTNO = D.DEPTNO
WHERE COMM IS NOT NULL;
ENAME DEPTNO LOC COMM
---------- ---------- ------------- ----------
MILLER 10 NEW YORK 300
WARD 30 CHICAGO 500
TURNER 30 CHICAGO 0
ALLEN 30 CHICAGO 300
MARTIN 30 CHICAGO 1400
4. 이름 중간에 L자가 있는 직원에 대해 이름,업무,부서명,근무지 조회
SELECT ENAME,E.DEPTNO,D.LOC
FROM EMP E INNER JOIN DEPT D
ON E.DEPTNO = D.DEPTNO
WHERE INSTR(ENAME,'L') > 0;
ENAME DEPTNO LOC
---------- ---------- --------
ALLEN 30 CHICAGO
BLAKE 30 CHICAGO
CLARK 10 NEW YORK
MILLER 10 NEW YORK
5. 각 직원들에 대해서 그들의 관리자보다 먼저 입사한 직원에 대해
이름,입사일,관리자이름,관리자 입사일을 조회
SELECT E.ENAME,E.HIREDATE,E.MGR,X.ENAME,X.HIREDATE,X.EMPNO
FROM EMP E INNER JOIN EMP X
ON E.MGR = X.EMPNO
WHERE E.HIREDATE < X.HIREDATE;
ENAME HIREDATE MGR ENAME HIREDATE EMPNO
---------- -------- ---------- ---------- -------- ----------
ALLEN 81/02/20 7698 BLAKE 81/05/01 7698
WARD 81/02/22 7698 BLAKE 81/05/01 7698
BLAKE 81/05/01 7839 KING 81/11/17 7839
JONES 81/04/02 7839 KING 81/11/17 7839
CLARK 81/06/09 7839 KING 81/11/17 7839
SMITH 80/12/17 7902 FORD 81/12/03 7902
6. 말단사원의 사번,이름,업무,부서번호,근무지를 조회
SELECT E.EMPNO,E.ENAME,E.JOB,E.DEPTNO,D.LOC
FROM EMP E INNER JOIN DEPT D
ON E.DEPTNO = D.DEPTNO
WHERE NOT EXISTS (SELECT EMPNO FROM EMP WHERE E.EMPNO = MGR);
SELECT E.EMPNO,E.ENAME,E.JOB,E.DEPTNO,D.LOC
FROM EMP E INNER JOIN DEPT D
ON E.DEPTNO = D.DEPTNO
WHERE EXISTS (SELECT EMPNO FROM EMP WHERE E.EMPNO <> MGR);
EMPNO ENAME JOB DEPTNO LOC
------ ---------- --------- ---------- --------
7844 TURNER SALESMAN 30 CHICAGO
7521 WARD SALESMAN 30 CHICAGO
7654 MARTIN SALESMAN 30 CHICAGO
7499 ALLEN SALESMAN 30 CHICAGO
7934 MILLER CLERK 10 NEW YORK
7369 SMITH CLERK 20 DALLAS
7876 ADAMS CLERK 20 DALLAS
7900 JAMES CLERK 30 CHICAGO
7. 근무지가 DALLAS인 직원의 사번,이름,급여,급여등급을 조회
SELECT E.EMPNO,E.ENAME,E.SAL,E.DEPTNO,S.GRADE,D.LOC
FROM EMP E INNER JOIN DEPT D
ON E.DEPTNO = D.DEPTNO
INNER JOIN SALGRADE S
ON D.LOC = 'DALLAS'
WHERE E.SAL BETWEEN S.LOSAL AND S.HISAL;
EMPNO ENAME SAL DEPTNO GRADE LOC
------ ---------- ---------- ---------- ---------- ------
7369 SMITH 800 20 1 DALLAS
7876 ADAMS 1100 20 1 DALLAS
7566 JONES 2975 20 4 DALLAS
7788 SCOTT 3000 20 4 DALLAS
7902 FORD 3000 20 4 DALLAS
8.
CREATE TABLE TBLBOOK(
AUTHOR VARCHAR2(15),
TITLE VARCHAR2(15)
);
INSERT INTO TBLBOOK VALUES('최주현', '하늘과 땅');
INSERT INTO TBLBOOK VALUES('최주현', '바다');
INSERT INTO TBLBOOK VALUES('유은정', '바다');
INSERT INTO TBLBOOK VALUES('박성우', '문');
INSERT INTO TBLBOOK VALUES('최주현', '문');
INSERT INTO TBLBOOK VALUES('박성우', '천국');
INSERT INTO TBLBOOK VALUES('최지은', '천국');
INSERT INTO TBLBOOK VALUES('최주현', '천국');
INSERT INTO TBLBOOK VALUES('박성우', '고슴도치');
INSERT INTO TBLBOOK VALUES('서금동', '나');
한권의 책에 대해 두명 이상의 작가가 쓴 책을 검색하시오
책이름 작가명 작가명
SELECT A.TITLE,A.AUTHOR,B.AUTHOR
FROM TBLBOOK A INNER JOIN TBLBOOK B
ON A.TITLE = B.TITLE
AND A.AUTHOR < B.AUTHOR;
TITLE AUTHOR AUTHOR
--------------- --------------- -------
바다 유은정 최주현
문 박성우 최주현
천국 최주현 최지은
천국 박성우 최지은
천국 박성우 최주현
9. 한권의 책에 대해 세명의 작가가 쓴 책을 검색하시오
책이름 작가명 작가명 작가명
-----------------------------------
###################################
6. 기타
----------------------------------- TicTacToe 게임
TicTacToe 게임은
두 명이 번갈아가며 3×3 판에 써서 같은 색상으로
가로, 세로, 혹은 대각선 상에 놓이도록 하는 놀이입니다.
이번에 만든 게임은 3 x 3 보다 더 넓은 판에서 컴퓨터와 할 수 있는 게임입니다.
맨 처음에는 사용자가 먼저 두게 되고,결과에 따라 먼저 두는 순서가 바뀝니다.
또한 이 게임은 판 안에 모든 색상이 변해야 끝나는 게임입니다.
클래스 명은 Tictactoe, JFRAME을 상속 받았고,
Tictactoe 클래스안에 모든 기능을 구현하였습니다.
TicTacToe 게임은
두 명이 번갈아가며 3×3 판에 써서 같은 색상으로
가로, 세로, 혹은 대각선 상에 놓이도록 하는 놀이입니다.
이번에 만든 게임은 3 x 3 보다 더 넓은 판에서 컴퓨터와 할 수 있는 게임입니다.
맨 처음에는 사용자가 먼저 두게 되고,결과에 따라 먼저 두는 순서가 바뀝니다.
또한 이 게임은 판 안에 모든 색상이 변해야 끝나는 게임입니다.
클래스 명은 Tictactoe, JFRAME을 상속 받았고,
Tictactoe 클래스안에 모든 기능을 구현하였습니다.
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class Tictactoe extends JFrame {
JPanel west, east;
JButton reset, end_game;
JLabel lb_win, lb_lose, lb_draw;
JLabel lb_win_num, lb_lose_num, lb_draw_num;
Random random;
boolean isTestMode; // 테스트 모드를 위해 사용
final int AI_NUM = 2; // ai가 둘때 사용하는 값
final int USER_NUM = 1; // user가 둘때 사용하는 값
final int INIT = 0; // 초기에 아무도 두지 않았을 때 사용하는 값
int win_cnt = 0, lose_cnt = 0, draw_cnt = 0; // 승, 패, 비김 값
boolean isUserFirst = true; // true면 user 먼저, 아니면 ai 먼저
boolean isEnd = false; // 게임의 종료 됨을 확인하기 위한 flag
int row_col = 3; // 기본 tictactoe 배열의 크기
JButton button[][]; // 버튼 UI
int[][] tictactoe; // tictactoe 배열, 누가 체크 했는지 이 배열로 확인
ImageIcon icon_user, icon_ai;
ButtonListener bl; // 버튼 리스너
// UI 생성자의 매개변수 num은 실행시 cmd argument로 입력 받아서, 게임의 크기를 결정
public Tictactoe(int num, boolean isTestMode) {
setTitle("TicTacToe - 모든 수를 전부 두어야 끝나는 게임");
if (num > 0)
row_col = num;
this.isTestMode = isTestMode;
button = new JButton[row_col][row_col];
tictactoe = new int[row_col][row_col];
west = new JPanel();
east = new JPanel();
random = new Random();
bl = new ButtonListener();
west.setLayout(new GridLayout(row_col, row_col));
for (int i = 0; i < button.length; i++) {
for (int j = 0; j < button[i].length; j++) {
button[i][j] = new JButton();
button[i][j].setForeground(Color.lightGray);
button[i][j].setBackground(Color.lightGray);
button[i][j].addActionListener(bl);
tictactoe[i][j] = INIT;
west.add(button[i][j]);
}
}
reset = new JButton("다시하기");
reset.setFont(new Font("", Font.BOLD, 30));
end_game = new JButton("종료");
end_game.setFont(new Font("", Font.BOLD, 30));
lb_win = new JLabel("Win(승)", JLabel.CENTER);
lb_win.setFont(new Font("", Font.BOLD, 30));
lb_lose = new JLabel("Lose(패)", JLabel.CENTER);
lb_lose.setFont(new Font("", Font.BOLD, 30));
lb_draw = new JLabel("Draw(비김)", JLabel.CENTER);
lb_draw.setFont(new Font("", Font.BOLD, 30));
lb_win_num = new JLabel();
lb_win_num.setFont(new Font("", Font.BOLD, 30));
lb_lose_num = new JLabel();
lb_lose_num.setFont(new Font("", Font.BOLD, 30));
lb_draw_num = new JLabel();
lb_draw_num.setFont(new Font("", Font.BOLD, 30));
lb_win_num.setHorizontalAlignment(JLabel.CENTER);
lb_lose_num.setHorizontalAlignment(JLabel.CENTER);
lb_draw_num.setHorizontalAlignment(JLabel.CENTER);
ButtonListener bl = new ButtonListener();
reset.addActionListener(bl);
end_game.addActionListener(bl);
east.setLayout(new GridLayout(4, 2, 2, 2));
east.add(reset);
east.add(end_game);
east.add(lb_win);
east.add(lb_win_num);
east.add(lb_lose);
east.add(lb_lose_num);
east.add(lb_draw);
east.add(lb_draw_num);
setLayout(new GridLayout(1, 2, 5, 5));
add(west);
add(east);
if (row_col <= 5) {
setBounds(200, 100, 700, 400);
} else if (row_col == 6) {
setBounds(200, 100, 800, 400);
} else if (row_col >= 7) {
setBounds(200, 100, 1000, 500);
}
setVisible(true);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
/*
* ai_up() 함수의 알고리즘 계획 - 현재 1,2번만 구현되어 있음, 아래 설명중 내꺼,나 는 컴퓨터,ai를 의미
* 방침 row_col이 홀,짝 인지 판별, 홀 - 가운데에 관련된 시나리오 필요, 홀 - 최대 둘 수 있는 수가 다르고, 짝 - 같음
* 이 게임은 한 사람이 둘 수 있는 최대수가 홀수-(row_col * row_col + 1)/2 = 먼저 둘때,1개 빼면 수는 두번째 둘때
* 1.내꺼-내꺼중에 행, 열, 대, 각선 중에서 row_col-1 개 만큼 내것이 채워져 있고 남은 공간이 비어 있으면 내가 둠
* 2.상대-1이 없으면 상대편 행, 열, 대, 각선 중에서 row_col-1 개 만큼 상대편 것이 채워져 있고 남은 공간이 비어 있으면 내가 둬서 막음
*
* 3.상대-2가 없으면 상대편이 둔 곳 중에 다음 수를 두면 행,열,대,각선 중에 row_col-1이 되는 곳이 두군 데 이상인 곳을 찾아서 막는다
* 4.내꺼-3이 없으면 내가 둘 수 중에 다음에 두면 행,열,대,각선 중에 row_col-1이 되는 곳이 두군 데 이상인 곳을 찾아서 둔다
* 5.내꺼-4가 없으면 이길 수 있는 경우의 수가 많은 곳에 둔다
*
* 이길 수 있는 경우의 수
* 5-1. 내가 둘 수 있는 곳이 여러개의 경우의 수로 이길 수 있는 경우
* 5-2. 1번을 충족하면서 상대편 말이 없는 경우
* 5-3. 가운데에서 가까운데 먼저 둔다
* 5-4. 나머지 빈 곳에 둔다
*/
void ai_up() {
int user_cnt = 0;
int ai_cnt = 0;
boolean endCheck = false;
//ai가 두기 전에 사용자가 이겼는지 체크
win_check();
if (isEnd){
isEnd = true;
}else {
// 1.내꺼-내꺼중에 행, 열, 대, 각선 중에서 row_col-1 개 만큼 내것이 채워져 있고 남은 공간이 비어 있으면 내가 둠
if(isTestMode)
System.out.println("ai_1-1");
if (endCheck == false) {
for (int i = 0; i < tictactoe.length; i++) {
int j = i;
if (tictactoe[j][i] == AI_NUM) {
ai_cnt++;
}
}
if (ai_cnt == row_col - 1) {
for (int i = 0; i < tictactoe.length; i++) {
int j = i;
if (tictactoe[j][i] == INIT) {
endCheck = true;
button[j][i].setBackground(Color.blue);
tictactoe[j][i] = AI_NUM;
}
}
}
ai_cnt = 0;
}
if(isTestMode)
System.out.println("ai_1-2");
if (endCheck == false) {
for (int i = 0; i < tictactoe.length; i++) {
int j = tictactoe.length - 1 - i;
if (tictactoe[j][i] == AI_NUM) {
ai_cnt++;
}
}
if (ai_cnt == row_col - 1) {
for (int i = 0; i < tictactoe.length; i++) {
int j = tictactoe.length - 1 - i;
if (tictactoe[j][i] == INIT) {
endCheck = true;
button[j][i].setBackground(Color.blue);
tictactoe[j][i] = AI_NUM;
}
}
}
ai_cnt = 0;
}
if(isTestMode)
System.out.println("ai_1-3");
if (endCheck == false) {
for (int i = 0; i < tictactoe.length; i++) {
for (int j = 0; j < tictactoe[i].length; j++) {
if (tictactoe[i][j] == AI_NUM) {
ai_cnt++;
}
}
if (ai_cnt == row_col - 1) {
for (int j = 0; j < tictactoe[i].length; j++) {
if (tictactoe[i][j] == INIT) {
endCheck = true;
button[i][j].setBackground(Color.blue);
tictactoe[i][j] = AI_NUM;
}
}
}
ai_cnt = 0;
if (endCheck == true)
break;
}
}
if(isTestMode)
System.out.println("ai_1-4");
if (endCheck == false) {
for (int i = 0; i < tictactoe.length; i++) {
for (int j = 0; j < tictactoe[i].length; j++) {
if (tictactoe[j][i] == AI_NUM) {
ai_cnt++;
}
}
if (ai_cnt == row_col - 1) {
for (int j = 0; j < tictactoe[i].length; j++) {
if (tictactoe[j][i] == INIT) {
endCheck = true;
button[j][i].setBackground(Color.blue);
tictactoe[j][i] = AI_NUM;
}
}
}
ai_cnt = 0;
if(endCheck == true)
break;
}
}
// 2.상대-1이 없으면 상대편 행, 열, 대, 각선 중에서 row_col-1 개 만큼 상대편 것이 채워져 있고 남은 공간이 비어 있으면 내가 둬서 막음
if(isTestMode)
System.out.println("ai_2-1");
if (endCheck == false) {
for (int i = 0; i < tictactoe.length; i++) {
int j = i;
if (tictactoe[j][i] == USER_NUM) {
user_cnt++;
}
}
if (user_cnt == row_col - 1) {
for (int i = 0; i < tictactoe.length; i++) {
int j = i;
if (tictactoe[j][i] == INIT) {
endCheck = true;
button[j][i].setBackground(Color.blue);
tictactoe[j][i] = AI_NUM;
}
}
}
user_cnt = 0;
}
if(isTestMode)
System.out.println("ai_2-2");
if (endCheck == false) {
for (int i = 0; i < tictactoe.length; i++) {
int j = tictactoe.length - 1 - i;
if (tictactoe[j][i] == USER_NUM) {
user_cnt++;
}
}
if (user_cnt == row_col - 1) {
for (int i = 0; i < tictactoe.length; i++) {
int j = tictactoe.length - 1 - i;
if (tictactoe[j][i] == INIT) {
endCheck = true;
button[j][i].setBackground(Color.blue);
tictactoe[j][i] = AI_NUM;
}
}
}
user_cnt = 0;
}
if(isTestMode)
System.out.println("ai_2-3");
if (endCheck == false) {
for (int i = 0; i < tictactoe.length; i++) {
for (int j = 0; j < tictactoe[i].length; j++) {
if (tictactoe[i][j] == USER_NUM) {
user_cnt++;
}
}
if (user_cnt == row_col-1) {
for (int j = 0; j < tictactoe[i].length; j++) {
if (tictactoe[i][j] == INIT) {
endCheck = true;
button[i][j].setBackground(Color.blue);
tictactoe[i][j] = AI_NUM;
}
}
}
user_cnt = 0;
if(endCheck == true)
break;
}
}
if(isTestMode)
System.out.println("ai_2-4");
if (endCheck == false) {
for (int i = 0; i < tictactoe.length; i++) {
for (int j = 0; j < tictactoe[i].length; j++) {
if (tictactoe[j][i] == USER_NUM) {
user_cnt++;
}
}
if (user_cnt == row_col - 1) {
for (int j = 0; j < tictactoe[i].length; j++) {
if (tictactoe[j][i] == INIT) {
endCheck = true;
button[j][i].setBackground(Color.blue);
tictactoe[j][i] = AI_NUM;
}
}
}
user_cnt = 0;
if(endCheck == true)
break;
}
}
// 우선 나머지는 random으로 돌림
if(isTestMode)
System.out.println("ai_random");
if(endCheck == false){
if(tictactoe[(row_col-1)/2][(row_col-1)/2] == INIT){
tictactoe[(row_col-1)/2][(row_col-1)/2] = AI_NUM;
button[(row_col-1)/2][(row_col-1)/2].setBackground(Color.blue);
}else{
for (;;) {
int i = random.nextInt(row_col);
int k = random.nextInt(row_col);
if (tictactoe[i][k] == INIT) {
button[i][k].setBackground(Color.blue);
tictactoe[i][k] = AI_NUM;
break;
}
}
}
}
}
// ai가 둔 뒤 승리 체크
win_check();
}
// 개발 초기에 AI가 RANDOM만 두도록 하게 만든 함수, 현재 사용 X
void ai_random() {
for (;;) {
win_check();
if (isEnd){
isEnd = true;
break;
}else {
int i = random.nextInt(row_col);
int k = random.nextInt(row_col);
if (tictactoe[i][k] == INIT) {
button[i][k].setBackground(Color.blue);
tictactoe[i][k] = AI_NUM;
win_check();
break;
}
}
}
}
void win_check() {
if (!isEnd) {
int user_cnt = 0;
int ai_cnt = 0;
int init_cnt = 0;
// 행 검사
for (int i = 0; i < tictactoe.length; i++) {
for (int j = 0; j < tictactoe[i].length; j++) {
if (tictactoe[i][j] == USER_NUM) {
user_cnt++;
} else if (tictactoe[i][j] == AI_NUM) {
ai_cnt++;
} else if (tictactoe[i][j] == INIT) {
init_cnt++;
}
}
if (user_cnt == row_col) {
end_game(USER_NUM);
return;
}
if (ai_cnt == row_col) {
end_game(AI_NUM);
return;
}
ai_cnt = 0;
user_cnt = 0;
}
user_cnt = 0;
ai_cnt = 0;
// 열 검사
for (int i = 0; i < tictactoe.length; i++) {
for (int j = 0; j < tictactoe[i].length; j++) {
if (tictactoe[j][i] == USER_NUM) {
user_cnt++;
} else if (tictactoe[j][i] == AI_NUM) {
ai_cnt++;
}
}
if (user_cnt == row_col) {
end_game(USER_NUM);
return;
}
if (ai_cnt == row_col) {
end_game(AI_NUM);
return;
}
ai_cnt = 0;
user_cnt = 0;
}
user_cnt = 0;
ai_cnt = 0;
// 대각선 X의 첫번째 획 검사
for (int i = 0; i < tictactoe.length; i++) {
int j = i;
if (tictactoe[j][i] == USER_NUM) {
user_cnt++;
} else if (tictactoe[j][i] == AI_NUM) {
ai_cnt++;
}
}
if (user_cnt == row_col) {
end_game(USER_NUM);
return;
}
if (ai_cnt == row_col) {
end_game(AI_NUM);
return;
}
user_cnt = 0;
ai_cnt = 0;
// 대각선 X의 두번째 획 검사
for (int i = 0; i < tictactoe.length; i++) {
int j = tictactoe.length - 1 - i;
if (tictactoe[j][i] == USER_NUM) {
user_cnt++;
} else if (tictactoe[j][i] == AI_NUM) {
ai_cnt++;
}
}
if (user_cnt == row_col) {
end_game(USER_NUM);
return;
}
if (ai_cnt == row_col) {
end_game(AI_NUM);
return;
}
// 비겼는지 검사
if (init_cnt == 0) {
end_game(INIT);
}
}
}
// win_check() 의 반복된 부분을 위해 새로 만든 메서드
// win_check() 에서 이기고, 지고, 비겼을 때 하는 일을 분리 시킴
void end_game(int num) {
if (!isEnd) {
if (num == USER_NUM) {
win_cnt++;
isUserFirst = false;
showMessage("이겼습니다.");
lb_win_num.setText(String.valueOf(win_cnt));
} else if (num == AI_NUM) {
lose_cnt++;
isUserFirst = true;
showMessage("졌습니다.");
lb_lose_num.setText(String.valueOf(lose_cnt));
} else if (num == INIT) {
draw_cnt++;
isUserFirst = !isUserFirst;
showMessage("비겼습니다.");
lb_draw_num.setText(String.valueOf(draw_cnt));
}
for (int i = 0; i < tictactoe.length; i++) {
for (int j = 0; j < tictactoe[i].length; j++) {
button[i][j].setEnabled(false);
}
}
isEnd = true;
}
}
void showMessage(String message) {
JOptionPane.showMessageDialog(this, message);
}
private class ButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
JButton button1 = (JButton) e.getSource();
// tictactoe 버튼을 눌렀을때
for (int i = 0; i < button.length; i++) {
for (int k = 0; k < button[i].length; k++) {
if (button1 == button[i][k]) {
if (tictactoe[i][k] == INIT) {
button1.setBackground(Color.red);
button1.setForeground(Color.black);
button1.setText("USER");
tictactoe[i][k] = USER_NUM;
//ai_random();
ai_up();
}
}
}
}
// reset 버튼을 눌렀을 때
if (button1 == reset) {
for (int i = 0; i < button.length; i++) {
for (int k = 0; k < button[i].length; k++) {
button[i][k].setEnabled(true);
button[i][k].setBackground(Color.lightGray);
button[i][k].setForeground(Color.lightGray);
button[i][k].setText("");
tictactoe[i][k] = INIT;
}
}
isEnd = false;
if (!isUserFirst) {
ai_random();
}
}
// 종료 버튼 눌렀을 때
if (button1 == end_game) {
dispose();
}
}
}
public static void main(String[] args) {
if (args.length > 0) {
int num = Integer.parseInt(args[0]);
if(args.length > 1){
new Tictactoe(num, true);
}else
new Tictactoe(num, false);
} else
new Tictactoe(3, false);
}
}
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class Tictactoe extends JFrame {
JPanel west, east;
JButton reset, end_game;
JLabel lb_win, lb_lose, lb_draw;
JLabel lb_win_num, lb_lose_num, lb_draw_num;
Random random;
boolean isTestMode; // 테스트 모드를 위해 사용
final int AI_NUM = 2; // ai가 둘때 사용하는 값
final int USER_NUM = 1; // user가 둘때 사용하는 값
final int INIT = 0; // 초기에 아무도 두지 않았을 때 사용하는 값
int win_cnt = 0, lose_cnt = 0, draw_cnt = 0; // 승, 패, 비김 값
boolean isUserFirst = true; // true면 user 먼저, 아니면 ai 먼저
boolean isEnd = false; // 게임의 종료 됨을 확인하기 위한 flag
int row_col = 3; // 기본 tictactoe 배열의 크기
JButton button[][]; // 버튼 UI
int[][] tictactoe; // tictactoe 배열, 누가 체크 했는지 이 배열로 확인
ImageIcon icon_user, icon_ai;
ButtonListener bl; // 버튼 리스너
// UI 생성자의 매개변수 num은 실행시 cmd argument로 입력 받아서, 게임의 크기를 결정
public Tictactoe(int num, boolean isTestMode) {
setTitle("TicTacToe - 모든 수를 전부 두어야 끝나는 게임");
if (num > 0)
row_col = num;
this.isTestMode = isTestMode;
button = new JButton[row_col][row_col];
tictactoe = new int[row_col][row_col];
west = new JPanel();
east = new JPanel();
random = new Random();
bl = new ButtonListener();
west.setLayout(new GridLayout(row_col, row_col));
for (int i = 0; i < button.length; i++) {
for (int j = 0; j < button[i].length; j++) {
button[i][j] = new JButton();
button[i][j].setForeground(Color.lightGray);
button[i][j].setBackground(Color.lightGray);
button[i][j].addActionListener(bl);
tictactoe[i][j] = INIT;
west.add(button[i][j]);
}
}
reset = new JButton("다시하기");
reset.setFont(new Font("", Font.BOLD, 30));
end_game = new JButton("종료");
end_game.setFont(new Font("", Font.BOLD, 30));
lb_win = new JLabel("Win(승)", JLabel.CENTER);
lb_win.setFont(new Font("", Font.BOLD, 30));
lb_lose = new JLabel("Lose(패)", JLabel.CENTER);
lb_lose.setFont(new Font("", Font.BOLD, 30));
lb_draw = new JLabel("Draw(비김)", JLabel.CENTER);
lb_draw.setFont(new Font("", Font.BOLD, 30));
lb_win_num = new JLabel();
lb_win_num.setFont(new Font("", Font.BOLD, 30));
lb_lose_num = new JLabel();
lb_lose_num.setFont(new Font("", Font.BOLD, 30));
lb_draw_num = new JLabel();
lb_draw_num.setFont(new Font("", Font.BOLD, 30));
lb_win_num.setHorizontalAlignment(JLabel.CENTER);
lb_lose_num.setHorizontalAlignment(JLabel.CENTER);
lb_draw_num.setHorizontalAlignment(JLabel.CENTER);
ButtonListener bl = new ButtonListener();
reset.addActionListener(bl);
end_game.addActionListener(bl);
east.setLayout(new GridLayout(4, 2, 2, 2));
east.add(reset);
east.add(end_game);
east.add(lb_win);
east.add(lb_win_num);
east.add(lb_lose);
east.add(lb_lose_num);
east.add(lb_draw);
east.add(lb_draw_num);
setLayout(new GridLayout(1, 2, 5, 5));
add(west);
add(east);
if (row_col <= 5) {
setBounds(200, 100, 700, 400);
} else if (row_col == 6) {
setBounds(200, 100, 800, 400);
} else if (row_col >= 7) {
setBounds(200, 100, 1000, 500);
}
setVisible(true);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
/*
* ai_up() 함수의 알고리즘 계획 - 현재 1,2번만 구현되어 있음, 아래 설명중 내꺼,나 는 컴퓨터,ai를 의미
* 방침 row_col이 홀,짝 인지 판별, 홀 - 가운데에 관련된 시나리오 필요, 홀 - 최대 둘 수 있는 수가 다르고, 짝 - 같음
* 이 게임은 한 사람이 둘 수 있는 최대수가 홀수-(row_col * row_col + 1)/2 = 먼저 둘때,1개 빼면 수는 두번째 둘때
* 1.내꺼-내꺼중에 행, 열, 대, 각선 중에서 row_col-1 개 만큼 내것이 채워져 있고 남은 공간이 비어 있으면 내가 둠
* 2.상대-1이 없으면 상대편 행, 열, 대, 각선 중에서 row_col-1 개 만큼 상대편 것이 채워져 있고 남은 공간이 비어 있으면 내가 둬서 막음
*
* 3.상대-2가 없으면 상대편이 둔 곳 중에 다음 수를 두면 행,열,대,각선 중에 row_col-1이 되는 곳이 두군 데 이상인 곳을 찾아서 막는다
* 4.내꺼-3이 없으면 내가 둘 수 중에 다음에 두면 행,열,대,각선 중에 row_col-1이 되는 곳이 두군 데 이상인 곳을 찾아서 둔다
* 5.내꺼-4가 없으면 이길 수 있는 경우의 수가 많은 곳에 둔다
*
* 이길 수 있는 경우의 수
* 5-1. 내가 둘 수 있는 곳이 여러개의 경우의 수로 이길 수 있는 경우
* 5-2. 1번을 충족하면서 상대편 말이 없는 경우
* 5-3. 가운데에서 가까운데 먼저 둔다
* 5-4. 나머지 빈 곳에 둔다
*/
void ai_up() {
int user_cnt = 0;
int ai_cnt = 0;
boolean endCheck = false;
//ai가 두기 전에 사용자가 이겼는지 체크
win_check();
if (isEnd){
isEnd = true;
}else {
// 1.내꺼-내꺼중에 행, 열, 대, 각선 중에서 row_col-1 개 만큼 내것이 채워져 있고 남은 공간이 비어 있으면 내가 둠
if(isTestMode)
System.out.println("ai_1-1");
if (endCheck == false) {
for (int i = 0; i < tictactoe.length; i++) {
int j = i;
if (tictactoe[j][i] == AI_NUM) {
ai_cnt++;
}
}
if (ai_cnt == row_col - 1) {
for (int i = 0; i < tictactoe.length; i++) {
int j = i;
if (tictactoe[j][i] == INIT) {
endCheck = true;
button[j][i].setBackground(Color.blue);
tictactoe[j][i] = AI_NUM;
}
}
}
ai_cnt = 0;
}
if(isTestMode)
System.out.println("ai_1-2");
if (endCheck == false) {
for (int i = 0; i < tictactoe.length; i++) {
int j = tictactoe.length - 1 - i;
if (tictactoe[j][i] == AI_NUM) {
ai_cnt++;
}
}
if (ai_cnt == row_col - 1) {
for (int i = 0; i < tictactoe.length; i++) {
int j = tictactoe.length - 1 - i;
if (tictactoe[j][i] == INIT) {
endCheck = true;
button[j][i].setBackground(Color.blue);
tictactoe[j][i] = AI_NUM;
}
}
}
ai_cnt = 0;
}
if(isTestMode)
System.out.println("ai_1-3");
if (endCheck == false) {
for (int i = 0; i < tictactoe.length; i++) {
for (int j = 0; j < tictactoe[i].length; j++) {
if (tictactoe[i][j] == AI_NUM) {
ai_cnt++;
}
}
if (ai_cnt == row_col - 1) {
for (int j = 0; j < tictactoe[i].length; j++) {
if (tictactoe[i][j] == INIT) {
endCheck = true;
button[i][j].setBackground(Color.blue);
tictactoe[i][j] = AI_NUM;
}
}
}
ai_cnt = 0;
if (endCheck == true)
break;
}
}
if(isTestMode)
System.out.println("ai_1-4");
if (endCheck == false) {
for (int i = 0; i < tictactoe.length; i++) {
for (int j = 0; j < tictactoe[i].length; j++) {
if (tictactoe[j][i] == AI_NUM) {
ai_cnt++;
}
}
if (ai_cnt == row_col - 1) {
for (int j = 0; j < tictactoe[i].length; j++) {
if (tictactoe[j][i] == INIT) {
endCheck = true;
button[j][i].setBackground(Color.blue);
tictactoe[j][i] = AI_NUM;
}
}
}
ai_cnt = 0;
if(endCheck == true)
break;
}
}
// 2.상대-1이 없으면 상대편 행, 열, 대, 각선 중에서 row_col-1 개 만큼 상대편 것이 채워져 있고 남은 공간이 비어 있으면 내가 둬서 막음
if(isTestMode)
System.out.println("ai_2-1");
if (endCheck == false) {
for (int i = 0; i < tictactoe.length; i++) {
int j = i;
if (tictactoe[j][i] == USER_NUM) {
user_cnt++;
}
}
if (user_cnt == row_col - 1) {
for (int i = 0; i < tictactoe.length; i++) {
int j = i;
if (tictactoe[j][i] == INIT) {
endCheck = true;
button[j][i].setBackground(Color.blue);
tictactoe[j][i] = AI_NUM;
}
}
}
user_cnt = 0;
}
if(isTestMode)
System.out.println("ai_2-2");
if (endCheck == false) {
for (int i = 0; i < tictactoe.length; i++) {
int j = tictactoe.length - 1 - i;
if (tictactoe[j][i] == USER_NUM) {
user_cnt++;
}
}
if (user_cnt == row_col - 1) {
for (int i = 0; i < tictactoe.length; i++) {
int j = tictactoe.length - 1 - i;
if (tictactoe[j][i] == INIT) {
endCheck = true;
button[j][i].setBackground(Color.blue);
tictactoe[j][i] = AI_NUM;
}
}
}
user_cnt = 0;
}
if(isTestMode)
System.out.println("ai_2-3");
if (endCheck == false) {
for (int i = 0; i < tictactoe.length; i++) {
for (int j = 0; j < tictactoe[i].length; j++) {
if (tictactoe[i][j] == USER_NUM) {
user_cnt++;
}
}
if (user_cnt == row_col-1) {
for (int j = 0; j < tictactoe[i].length; j++) {
if (tictactoe[i][j] == INIT) {
endCheck = true;
button[i][j].setBackground(Color.blue);
tictactoe[i][j] = AI_NUM;
}
}
}
user_cnt = 0;
if(endCheck == true)
break;
}
}
if(isTestMode)
System.out.println("ai_2-4");
if (endCheck == false) {
for (int i = 0; i < tictactoe.length; i++) {
for (int j = 0; j < tictactoe[i].length; j++) {
if (tictactoe[j][i] == USER_NUM) {
user_cnt++;
}
}
if (user_cnt == row_col - 1) {
for (int j = 0; j < tictactoe[i].length; j++) {
if (tictactoe[j][i] == INIT) {
endCheck = true;
button[j][i].setBackground(Color.blue);
tictactoe[j][i] = AI_NUM;
}
}
}
user_cnt = 0;
if(endCheck == true)
break;
}
}
// 우선 나머지는 random으로 돌림
if(isTestMode)
System.out.println("ai_random");
if(endCheck == false){
if(tictactoe[(row_col-1)/2][(row_col-1)/2] == INIT){
tictactoe[(row_col-1)/2][(row_col-1)/2] = AI_NUM;
button[(row_col-1)/2][(row_col-1)/2].setBackground(Color.blue);
}else{
for (;;) {
int i = random.nextInt(row_col);
int k = random.nextInt(row_col);
if (tictactoe[i][k] == INIT) {
button[i][k].setBackground(Color.blue);
tictactoe[i][k] = AI_NUM;
break;
}
}
}
}
}
// ai가 둔 뒤 승리 체크
win_check();
}
// 개발 초기에 AI가 RANDOM만 두도록 하게 만든 함수, 현재 사용 X
void ai_random() {
for (;;) {
win_check();
if (isEnd){
isEnd = true;
break;
}else {
int i = random.nextInt(row_col);
int k = random.nextInt(row_col);
if (tictactoe[i][k] == INIT) {
button[i][k].setBackground(Color.blue);
tictactoe[i][k] = AI_NUM;
win_check();
break;
}
}
}
}
void win_check() {
if (!isEnd) {
int user_cnt = 0;
int ai_cnt = 0;
int init_cnt = 0;
// 행 검사
for (int i = 0; i < tictactoe.length; i++) {
for (int j = 0; j < tictactoe[i].length; j++) {
if (tictactoe[i][j] == USER_NUM) {
user_cnt++;
} else if (tictactoe[i][j] == AI_NUM) {
ai_cnt++;
} else if (tictactoe[i][j] == INIT) {
init_cnt++;
}
}
if (user_cnt == row_col) {
end_game(USER_NUM);
return;
}
if (ai_cnt == row_col) {
end_game(AI_NUM);
return;
}
ai_cnt = 0;
user_cnt = 0;
}
user_cnt = 0;
ai_cnt = 0;
// 열 검사
for (int i = 0; i < tictactoe.length; i++) {
for (int j = 0; j < tictactoe[i].length; j++) {
if (tictactoe[j][i] == USER_NUM) {
user_cnt++;
} else if (tictactoe[j][i] == AI_NUM) {
ai_cnt++;
}
}
if (user_cnt == row_col) {
end_game(USER_NUM);
return;
}
if (ai_cnt == row_col) {
end_game(AI_NUM);
return;
}
ai_cnt = 0;
user_cnt = 0;
}
user_cnt = 0;
ai_cnt = 0;
// 대각선 X의 첫번째 획 검사
for (int i = 0; i < tictactoe.length; i++) {
int j = i;
if (tictactoe[j][i] == USER_NUM) {
user_cnt++;
} else if (tictactoe[j][i] == AI_NUM) {
ai_cnt++;
}
}
if (user_cnt == row_col) {
end_game(USER_NUM);
return;
}
if (ai_cnt == row_col) {
end_game(AI_NUM);
return;
}
user_cnt = 0;
ai_cnt = 0;
// 대각선 X의 두번째 획 검사
for (int i = 0; i < tictactoe.length; i++) {
int j = tictactoe.length - 1 - i;
if (tictactoe[j][i] == USER_NUM) {
user_cnt++;
} else if (tictactoe[j][i] == AI_NUM) {
ai_cnt++;
}
}
if (user_cnt == row_col) {
end_game(USER_NUM);
return;
}
if (ai_cnt == row_col) {
end_game(AI_NUM);
return;
}
// 비겼는지 검사
if (init_cnt == 0) {
end_game(INIT);
}
}
}
// win_check() 의 반복된 부분을 위해 새로 만든 메서드
// win_check() 에서 이기고, 지고, 비겼을 때 하는 일을 분리 시킴
void end_game(int num) {
if (!isEnd) {
if (num == USER_NUM) {
win_cnt++;
isUserFirst = false;
showMessage("이겼습니다.");
lb_win_num.setText(String.valueOf(win_cnt));
} else if (num == AI_NUM) {
lose_cnt++;
isUserFirst = true;
showMessage("졌습니다.");
lb_lose_num.setText(String.valueOf(lose_cnt));
} else if (num == INIT) {
draw_cnt++;
isUserFirst = !isUserFirst;
showMessage("비겼습니다.");
lb_draw_num.setText(String.valueOf(draw_cnt));
}
for (int i = 0; i < tictactoe.length; i++) {
for (int j = 0; j < tictactoe[i].length; j++) {
button[i][j].setEnabled(false);
}
}
isEnd = true;
}
}
void showMessage(String message) {
JOptionPane.showMessageDialog(this, message);
}
private class ButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
JButton button1 = (JButton) e.getSource();
// tictactoe 버튼을 눌렀을때
for (int i = 0; i < button.length; i++) {
for (int k = 0; k < button[i].length; k++) {
if (button1 == button[i][k]) {
if (tictactoe[i][k] == INIT) {
button1.setBackground(Color.red);
button1.setForeground(Color.black);
button1.setText("USER");
tictactoe[i][k] = USER_NUM;
//ai_random();
ai_up();
}
}
}
}
// reset 버튼을 눌렀을 때
if (button1 == reset) {
for (int i = 0; i < button.length; i++) {
for (int k = 0; k < button[i].length; k++) {
button[i][k].setEnabled(true);
button[i][k].setBackground(Color.lightGray);
button[i][k].setForeground(Color.lightGray);
button[i][k].setText("");
tictactoe[i][k] = INIT;
}
}
isEnd = false;
if (!isUserFirst) {
ai_random();
}
}
// 종료 버튼 눌렀을 때
if (button1 == end_game) {
dispose();
}
}
}
public static void main(String[] args) {
if (args.length > 0) {
int num = Integer.parseInt(args[0]);
if(args.length > 1){
new Tictactoe(num, true);
}else
new Tictactoe(num, false);
} else
new Tictactoe(3, false);
}
}
-----------------------------------
'OpenFrameWork' 카테고리의 다른 글
오픈프레임워크_Day26 (0) | 2015.04.20 |
---|---|
오픈프레임워크_Day25 (0) | 2015.04.20 |
오픈프레임워크_Day23 (0) | 2015.04.20 |
오픈프레임워크_Day22 (0) | 2015.04.20 |
오픈프레임워크_Day21 (0) | 2015.04.20 |