### : 목차 구분 기호
--- : 목차 내에 항목 구분 기호

목차
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

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

급여와 보너스가 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

급여와 보너스를 하나씩 비교하니까 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

----------------------------------- 
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);

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

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
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

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

테이블에 별명을 줄 수 있음
그러나 별명을 주면 무줘건 별명만으로 사용해야 한다
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

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

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

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

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

세개의 테이블 조인
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

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

직원의 사번,이름,급여,급여등급을 조회 - 공통필드가 없음
SELECT EMPNO,ENAME,SAL,GRADE,LOSAL,HISAL
FROM EMP INNER JOIN SALGRADE
ON SAL >= LOSAL AND SAL <= HISAL;

 EMPNO ENAME             SAL      GRADE      LOSAL      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
----------------------------------- 
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

SELECT DEPTNO FROM EMP;

 DEPTNO
-------
     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

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

SELECT DEPTNO FROM DEPT
INTERSECT
SELECT DEPTNO FROM EMP;

 DEPTNO
-------
     10
     20
     30

SELECT DEPTNO FROM DEPT
MINUS
SELECT DEPTNO FROM EMP;

 DEPTNO
-------
     40
----------------------------------- 
-----------------------------------
-----------------------------------
###################################
2. 설정 및 그 밖에
-----------------------------------
----------------------------------- 
----------------------------------- 
----------------------------------- 
###################################
3. 소스코드 또는 실습 
-----------------------------------
-----------------------------------  
###################################
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('서금동', '나');

한권의 책에 대해 두명 이상의 작가가 쓴 책을 검색하시오

책이름     작가명     작가명

9. 한권의 책에 대해 세명의 작가가 쓴 책을 검색하시오
책이름     작가명     작가명     작가명
-----------------------------------
프로젝트에 관한 간단한 설명서 만들기
###################################
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. 한권의 책에 대해 세명의 작가가 쓴 책을 검색하시오
책이름 작가명 작가명 작가명
-----------------------------------
###################################
6. 기타
----------------------------------- 
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);
     }
}

----------------------------------- 


'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
,