JAVA 웹개발 과정 국비 18일차 정리
18일차
※ 배우는 과정이므로 정확하지 않을 수 있습니다.
잘못된 점은 알려주시면 수정하도록 하겠습니다!
1. 그룹화 (GROUP BY + HAVING)
1) GROUP BY
특정 컬럼을 기준으로 그룹화시켜서 데이터를 만들어내는 기법
직원별 급여 목록은 아래와 같이 구할 수 있다.
SELECT emp_name, salary FROM employee;
전직원의 급여 합계는 아래와 같이 구할 수 있다.
SELECT SUM(salary) FROM employee;
그렇다면, 부서별 급여 합계는 어떻게 구할 수 있을까?
이때, GROUP BY를 이용한다.
- GROUP BY 뜻 : “~별로 헤쳐 모여~!!!”
- GROUP BY를 쓰면 SELECT 뒤 데이터 하나하나 값 출력 불가능하고, 그룹화 된 값만 출력 가능하다.
- 부가적인 효과 : 중복 값 제거
- 2개 이상 사용 가능하다.
SELECT
dept_code,
TO_CHAR(SUM(salary),'L999,999,999') AS "부서별 급여합계",
COUNT(*)||'명' AS "부서별 인원수"
FROM employee
GROUP BY dept_code -- 부서코드별로 헤쳐모여~!!
ORDER BY 1;
부서 안에 직원들이 다 들어있는 그림을 연상하면 이해하기 쉽다.
부서코드와 SUM(salary)를 그 부서 안에 사람들에게 물어본다.
-- 부서코드별 보너스를 받는 사람의 인원수
-- 0을 출력 안하는 쿼리
SELECT dept_code, COUNT(*)||'명' AS "보너스 받는 인원 수"
FROM employee WHERE bonus IS NOT NULL GROUP BY dept_code ORDER BY 1;
-- 0도 출력하는 쿼리
SELECT COUNT(bonus) FROM employee GROUP BY dept_code;
-- 부서별로 그룹화, 직급별로 그룹화(이중 그룹화)
SELECT dept_code, job_code , SUM(salary) AS "부서 내 직급별 합계"
FROM employee GROUP BY dept_code, job_code
ORDER BY 1;
2) HAVING
그룹화 데이터에 대한 조건을 부여하는 구문
부서 내 급여 평균이 250만원보다 작은 부서만 선별해서 보고싶다고 하자.
① WHERE절 = 조건?
조건이니까 WHERE절을 써서 쿼리문을 만들면 되겠지?
SELECT
dept_code,
FLOOR(AVG(salary))
FROM employee
WHERE AVG(salary) < 2500000 -- WHERE절?
GROUP BY dept_code
ORDER BY 1;
언뜻보면 맞는 쿼리문 처럼 보이지만, 규칙 상 WHERE절에 그룹함수는 사용할 수 없으므로 에러가 난다.
② WHERE절 조건을 다르게?
그렇다면 WHERE절의 조건을 다르게 하면 어떨까?
SELECT
dept_code,
FLOOR(AVG(salary))
FROM employee
WHERE salary < 2500000 -- 조건을 다르게?
GROUP BY dept_code
ORDER BY 1;
그러나 이렇게하면, 급여가 250만원보다 작은 직원을 뽑아 그룹화를 진행하게되어, 급여가 250만이 넘은 직원들은 아예 빠지게 된다.
구하려고 하는 값은 전체 직원의 부서에서 조건에 맞는 부서이기 때문에 맞지 않는다.
③ HAVING 문 사용
따라서, 그룹화 후에 조건을 달고 싶다면 HAVING절을 사용해야 한다.
SELECT
dept_code,
FLOOR(AVG(salary))
FROM employee
GROUP BY dept_code
HAVING AVG(salary) < 2500000 -- HAVING절!
ORDER BY 1;
3) 쿼리 실행 순서
WHERE절 다음 GROUP BY가 진행된다는 것은 어떻게 알 수 있을까?
바로 쿼리 진행 순서가 정해져있기 때문이다.
SELECT 쿼리 실행 순서는 아래와 같다.
FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY
SELECT salary 급여 FROM employee WHERE 급여 < 2000000; --불가능함
SELECT salary 급여 FROM employee ORDER BY 급여; --가능
실행 순서를 잘 외워둔다면, 위와 같은 쿼리문에서 실수할 확률이 줄어든다.
2. JOIN
여러 테이블의 레코드를 조합해서 의미있는 ResultSet을 만들어내는 문법
다중 JOIN도 존재한다.
1) CROSS JOIN (카티션곱)
job 테이블과 department 테이블이 있다.
두 테이블을 그냥 합쳐서 보고싶다면 CROSS JOIN을 해주면 된다.
교집합이라고 생각할 수 있다.
두 테이블에 대한 모든 정보를 합치는 방법
① ORACLE 쿼리 문법
카티션곱이라고 불린다.
SELECT * FROM job, department;
② ANSI 표준 쿼리 문법
CROSS JOIN이라고 불린다.
SELECT * FROM job CROSS JOIN department;
2) INNER JOIN
특정 조건을 이용해서 의미있는 데이터를 만드는 것
조건문에 무조건 =을 써주지는 않지만, =가 올때는 ‘두개 값이 같으면 연결해라’라고 해석하면 조금 더 쉽게 이해할 수 있다.
① ORACLE 쿼리 문법
employee 테이블에도 job_code 컬럼이 있고, job 테이블에도 job_code가 있을 때, 간단하게 아래와 같이 쓰면 오류가 난다.
이때는 테이블에 별명을 만들어서 컬럼명 앞에 붙여줘야 한다.
SELECT emp_name, job_name FROM employee, job WHERE job_code=job_code;
-- column ambiguously defined : 컬럼이 애매하게 정의되었다 (오류!)
SELECT emp_name, job_name FROM employee e, job j
WHERE e.job_code=j.job_code;
② ANSI 표준 쿼리 문법
같은 컬럼명을 공유할 때는 특별하게 ON 대신 USING을 쓸 수 있다.
선택사항이므로 꼭 USING을 쓸 필요는 없다.
일반적으로 JOIN만 쓸때는 INNER JOIN을 의미한다.
-- ON 사용
SELECT emp_name, job_name FROM employee e (INNER) JOIN job j
ON (e.job_code=j.job_code);
-- USING 사용
SELECT emp_name, job_name FROM employee (INNER) JOIN job
USING (job_code);
3) LEFT OUTER JOIN
INNER JOIN을 하니 NULL값을 가진 데이터는 아예 출력이 되지 않는다는 단점이 있다.
이 때 OUTER JOIN이 하나의 방법이 될 수 있다.
왼쪽 테이블의 값을 전부 나오게 하는 방법
① ORACLE 쿼리 문법
오른쪽 조건에 (+)를 붙여준다.
(+)
뜻은 ‘다른 테이블 값에 맞는 데이터가 없을 때 NULL 값으로 그냥 채워줘라!’라는 뜻. ‘
SELECT emp_name, dept_title FROM employee e,department d
WHERE e.dept_code = d.dept_id(+);
② ANSI 표준 쿼리 문법
OUTER는 써도 되고 안써도 된다.
SELECT emp_name, dept_title FROM employee e LEFT (OUTER) JOIN department d
ON (e.dept_code=d.dept_id);
4) RIGHT OUTER JOIN
LEFT OUTER JOIN의 반대 개념이다.
오른쪽 테이블의 값을 전부 나오게 하는 방법
① ORACLE 쿼리 문법
왼쪽 조건에 (+)를 붙여준다.
(+)
뜻은 ‘다른 테이블 값에 맞는 데이터가 없을 때 NULL 값으로 그냥 채워줘라!’라는 뜻. ‘
SELECT emp_name, dept_title FROM employee e,department d
WHERE e.dept_code(+) = d.dept_id;
② ANSI 표준 쿼리 문법
OUTER는 써도 되고 안써도 된다.
SELECT emp_name, dept_title FROM employee e RIGHT (OUTER) JOIN department d
ON (e.dept_code=d.dept_id);
5) FULL OUTER JOIN
양쪽 테이블의 값을 전부 나오게 하는 방법
① ORACLE 쿼리 문법
ORACLE 쿼리 문법에는 FULL OUTER JOIN이 없다.
② ANSI 표준 쿼리 문법
OUTER는 써도 되고 안써도 된다.
SELECT emp_name, dept_title FROM employee e FULL OUTER JOIN department d
ON (e.dept_code=d.dept_id);
6) SELF JOIN
같은 테이블을 JOIN 하여 사용하는 방법
특정 문법이 존재하는 것이 아니라 자기 자신을 참조하면 그게 SELF JOIN이다.
‘송종기’의 manager_id(직속상사)는 200이다.
emp_id에서 200을 찾으면… 음 ‘선동일’이군!
manager_id 처럼 숫자가 아닌 사람 이름이 바로 나오면 좋을텐데..
SELECT emp_id, emp_name, manager_id FROM employee
WHERE manager_id=emp_id;
WHERE절에 조건을 달아보았지만 나오지 않았다.
같은 행에서 emp_id와 manager_id가 같은 사람을 찾는 것이기 때문에 당연히 그런 사람은 없었다.
그럼 어떻게 해야할까?
같은 employee 테이블을 e1, e2로 나누어서 비교하는 것이다.
e1테이블과 e2테이블이라는 같은 테이블을 비교하면서 e1의 manager_id와 e2의 emp_id가 같아질 때 e2.emp_name을 출력한다
① ORACLE 쿼리 문법
SELECT e1.emp_id, e1.emp_name "직원명", e2.emp_name "상사이름"
FROM employee e1, employee e2
WHERE e1.manager_id=e2.emp_id;
② ANSI 표준 쿼리 문법
SELECT e1.emp_id, e1.emp_name "직원명", e2.emp_name "상사이름"
FROM employee e1 JOIN employee e2
ON (e1.manager_id=e2.emp_id);
댓글남기기