ANSI SQL INNER JOIN
Inner Join은 서로 조건에 매칭되는 것만 엮어 조회한다.
1. Equi Join
2. Non-Equin Join
3. Self-Join
Oracle Outer Join에서는, (+) 연산자 사용
반드시, 한 쪽 테이블에서만 사용가능ANSI Outer Join에서는, LEFT / RIGHT / FULL 키워드 사용
어느 한 쪽 테이블 또는 양 쪽 테이블에서 모두 사용가능LEFT OUTER JOIN :
LEFT로 지정된 테이블1의 데이터를, 테이블2의 조인조건의
일치여부와 상관없이 모두 출력RIGHT OUTER JOIN :
RIGHT로 지정된 테이블2의 데이터를, 테이블1의 조인조건의
일치여부와 상관없이 모두 출력FULL OUTER JOIN :
LEFT OUTER JOIN + RIGHT OUTER JOIN
양쪽 테이블의 데이터를, 조인조건 일치여부와 상관없이 모두 출력Oracle Outer Join 보다 향상(FULL이 있어서)
조인조건 명시할 때, ON절 또는 USING절 사용가능
(지금 예제가 의미있는 데이터를 살리는것은 아니다. )
SELECT
e.last_name AS 사원명,
m.last_name AS 관리자명
FROM
-- 일치하는 데이터가 없는 테이블의 별칭이 e를 가진 LEFT
-- 이기 때문에, LEFT OUTER JOIN 지정하고, ON 절을 사용하여
-- 조인조건 지정.
employees e LEFT OUTER JOIN employees m
-- employees e LEFT JOIN employees m -- OUTER 키워드 생략가능(하지만 생략하지마라)
-- employees e RIGHT OUTER JOIN employees m
-- employees e RIGHT JOIN employees m -- OUTER 키워드 생략가능
-- employees e FULL OUTER JOIN employees m
-- employees e FULL JOIN employees m -- OUTER 키워드 생략가능(자바 람다식 외에 생략하지마라)
ON e.manager_id = m.employee_id;
(목적은 셀프조인과 같음)
쿼리안에 하나의 쿼리를 더 만든다.
- Join은 한 개 이상의 테이블에서, 원하는 데이터를 조회
- 서브쿼리(=부속질의)는, 하나의 SELECT 문장 만으로 원하는
데이터를 조회할 수 없을 때 사용하는 방법 (셀프조인!을 쓰는 이유와 같음)- 한 개 이상의 SELECT문장을, 하나로 합쳐서, 하나의 실행가능
한 문장으로 만들어, 원하는 데이터를 조회하는 방법- 종류:
(1) 상관 부속질의(안쪽의 셀렉문과 바깥쪽의 셀렉문이 관련성이 있으면 상관)
- 서브쿼리(=부속질의)의 단독 수행이 불가능한 경우
- 메인쿼리의 데이터가 있어야 실행가능한 경우로,
- 메인쿼리가 먼저 수행되고, 차례대로 서브쿼리가 수행됨
- 메인쿼리의 결과가 서브쿼리에 전달되어, 서브쿼리 수행(순서)
(2) 비상관 부속질의(바깥쪽 안쪽의 셀렉문이 관련이 없습니다)
- 서브쿼리(=부속질의)의 단독 수행이 가능한 경우로 ,
- 서브쿼리가 먼저 수행된 다음에, 메인쿼리가 수행됨
- 서브쿼리의 결과가 메인쿼리에 전달되어 실행됨(순서/ 단 한 번 실행시켜서 발생된 결과를 메인에 전달)- 사실상, 서브쿼리(=부속질의)는, SELECT 문의 모든 절(clause)
에서 뿐만 아니라, 모든 DML문장에서도 사용가능하다!!! (주의)- 반드시 소괄호()를 사용해야 함.
- 구분: 서브쿼리가 실행되어 반환된 행의 개수에 따라,
(1) 단일 행 서브쿼리 (스칼라)
- 서브쿼리 실행 결과가 한 개의 행 반환.
- 메인쿼리에서 사용가능 연산자:
비교 연산자 (=, !=, <, >, <=, >=)
(2) 복수 행 서브쿼리
- 서브쿼리 실행 결과가 복수 개의 행 반환.
- 메인쿼리에서 사용가능 연산자:
IN, ANY, ALL, EXISTS 등- 서브쿼리 사용시, 가장 주의해야 할 점: 사용할 연산자
사용된 연산자에 따라, 위 '아'와 같이 행 반환
-- ------------------------------------------------------
-- * 하나의 SELECT문장만으로는 조회불가:
-- 가. 먼저, 'Whalen'의 월급이 얼마나인지 알아야 함. (SELECT 1)
-- 나. 조회한 'Whalen'의 월급보다 많은 월급을 받는 사원조회가능 (SELECT 2)
-- ------------------------------------------------------
-- SELECT #1: Whalen 의 월급조회(4400)
SELECT
salary
FROM
employees
WHERE
last_name = 'Whalen';
-- SELECT #2: Whalen 보다 월급을 많이 받는 사원 조회
SELECT
last_name,
salary
FROM
employees
WHERE
salary >= 4400; -- Whalen의 월급지정
-- ------------------------------------------------------
-- 위 #1과 같이, 하나 이상의 SELECT 문장이 있어야만, 원하는 결과
-- 를 조회가능한 경우에, 서브쿼리(=부속질의) 사용가능.
--
-- 즉, 서브쿼리는, 여러 번의 SELECT 문장을 수행해야 얻을 수 있는
-- 결과를, 하나의 중첩된(nested) SELECT 문장으로 만들어, 원하는
-- 결과를 쉽게 조회가능하게 함.
-- ------------------------------------------------------
SELECT -- 메인쿼리
last_name,
salary
FROM
employees
WHERE
-- 2nd. Whalen 보다 많은 월급여를 받는 사원조회
salary >= (
-- 서브쿼리(= 비상관 부속질의): (단 한번)
-- a. 단독 수행에 지장없음
-- b. Whalen의 월급여가 메인쿼리에 전달됨
SELECT salary
FROM employees
WHERE last_name = 'Whalen' -- 1st. Whalen 의 월급여 획득
);
- 하나의 행을 반환
- 반드시 단일 행 서브쿼리를 사용해야만 하는 경우:
- 기본키(Primary Key)를 이용하는 경우
- 그룹함수(MAX, MIN, SUM 등)를 이용하는 경우
-- 평균 급여를 먼저 구하기 위해, 단일 행 서브쿼리 및 그룹함수 AVG 사용
-- 따라서, 메인쿼리에서 사용가능한 연산자는 하나의 값과 비교하는 비교연산자임!
SELECT
last_name,
salary,
( SELECT avg(salary) FROM employees ) AS 평균급여
FROM
employees
WHERE
-- 메인쿼리: 단일행 서브쿼리가 사용되었으므로, 단일값과 비교가능한, 비교연산자 사용가능.
salary >= (
-- 단일 행 비상관 서브쿼리: 모든 사원의 평균 월급여 반환
-- 메인쿼리로 결과값 전달
SELECT
avg(salary)
FROM
employees
);
SELECT
last_name,
salary
FROM
employees
WHERE
-- 메인쿼리: 단일행 서브쿼리가 사용되었으므로, 단일값과 비교가능한, 비교연산자 사용가능
salary = (
-- 단일 행 비상관 서브쿼리: 100번 부서의 최대 월급여 반환
-- 메인쿼리로 결과값 전달
SELECT
max(salary)
FROM
employees
WHERE
department_id = 100
);
SELECT
-- 최종적으로 선택된, 각 부서의 번호와 최소 월급여 출력
department_id,
min(salary)
FROM
employees
GROUP BY
department_id -- 부서별 그룹 생성
HAVING
-- 메인쿼리 2차 필터링: 조건에 부합하는 그룹만 필터링
-- 단일행 서브쿼리가 사용되었으므로, 단일 값과 비교가능한
-- 비교연산자 사용가능
min(salary) > (
-- 단일 행 비상관 서브쿼리: 100번 부서의 최대 월급여 반환
-- 메인쿼리로 결과값 전달
SELECT
max(salary)
FROM
employees
WHERE
department_id = 100
);
SELECT
last_name,
hire_date
FROM
employees
WHERE
-- 메인쿼리 1차 필터링: 단일행 서브쿼리가 사용되었으므로, 단일 값과 비교가능한, 비교연산자 사용가능
hire_date > (
-- 단일 행 비상관 서브쿼리: Whalen의 채용일자 반환
-- 메인쿼리로 결과값 전달
SELECT
hire_date -- 현재시간과 가까워질수록 채용일이 늦은거
FROM
employees
WHERE
last_name = 'Whalen'
);
매개값 조사해 true 또는 false를 리턴할 때 사용
public class PridicateEx {
private static List<Student> list =
(List<Student>) Arrays.asList(
new Student("김영희","남자" , 80),
new Student("진들레","여자" , 100),
new Student("배카비","여자" , 84),
new Student("구카비","남자" , 95),
new Student("김뚝백","남자" , 24)
);
public static void main(String[] args) {
// boolean test(T t);
double maleAvg = avg(t -> t.getGender().equals("여자"));
System.out.println(maleAvg);
}// main
public static double avg(Predicate<Student> predicate) {
int count = 0 , sum = 0;
for(Student student : list) {
if(predicate.test(student)) {
count++;
sum += student.getPoint();
} // if
}// enhanced for
return (double) sum / count;
}// avg
}//end class
@Getter
@AllArgsConstructor
public class Student {
private String name;
private String gender;
private int point;
}
- 함수적 인터페이스가 가지고 있는 디폴트 메소드
- 두 개의 함수적 인터페이스를 순차적으로 연결해 실행
- 첫 번째 리턴값을 두 번째 매개값으로 제공해 최종 결과값 리턴
- andThen()과 compose()의 차이점 -> 어떤 함수적 인터페이스부터 처리하느냐
@ToString
@Getter
@AllArgsConstructor
public class Address {
private String country;
private String city;
}
@ToString
@Getter
@AllArgsConstructor
public class Member {
private String name;
private String id;
private Address adress;
}
public class consumerAndThenExample {
public static void main(String[] args) {
// TODO Auto-generated method stub
Consumer<Member> consumerA = (m) -> System.out.println("consumerA: " + m.getName());
Consumer<Member> consumerB = (m) -> System.out.println("consumerB: " + m.getId());
Consumer<Member> consumerC = (m) -> System.out.println("consumerC: " + m.getAdress());
// Consumer<Member> Consumer.andThen(Consumer<? super Member> after)
Consumer<Member> consumerAB = consumerA.andThen(consumerB);
Consumer<Member> consumerABC = consumerAB.andThen(consumerC);
Address address = new Address("대한민국", "서울");
Member member = new Member("홍길동", "hong", address);
System.out.println("1. member: " + member);
consumerABC.accept(member); //람다 세개를 연결해부렀어
// ----------
// 콘솔 출력 결과:
// 1. member: Member(name=홍길동, id=hong, adress=Address(country=대한민국, city=서울))
// consumerA: 홍길동
// consumerB: hong
// consumerC: Address(country=대한민국, city=서울)
}// main
}// end class
결과는 같음 어느것부터 시작하는지에 따름
public class FunctionAndThenEx {
public static void main(String[] args) {
Function<Member, Address> functionA;
Function<Address, String> functionB;
Function<Member, String> functionAB;
String city;
// R apply(T t);
functionA = m -> m.getAdress(); // Member -> Address
functionB = a -> a.getCity();// Address -> String(City)
functionAB = functionA.andThen(functionB);
Address address = new Address("대한민국", "서울");
Member member = new Member("홍길동", "hong", address);
city = functionAB.apply(member);
System.out.println("거주도시: " + city);
// ---
functionAB = functionB.compose(functionA);
city = functionAB.apply(member);
System.out.println("거주도시: " + city);
}// main
} // end class