41일차 DB 안시조인 아우터,서브쿼리/ 자바 람다 predicate,메소드

쿠우·2022년 5월 24일
0

ANSI SQL INNER JOIN
Inner Join은 서로 조건에 매칭되는 것만 엮어 조회한다.
1. Equi Join
2. Non-Equin Join
3. Self-Join


DB

안시 조인 남은 부분

-아우터 조인 { LEFT | RIGHT | FULL }

  • 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 등
  • 서브쿼리 사용시, 가장 주의해야 할 점: 사용할 연산자
    사용된 연산자에 따라, 위 '아'와 같이 행 반환

-사원정보에서, 'Whalen'보다 많은 월급을 받는 사원조회 #1(서브쿼리 필요성)

-- ------------------------------------------------------
-- * 하나의 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의 월급지정

-사원정보에서, 'Whalen'보다 많은 월급을 받는 사원조회 #2(서브쿼리 사용)

-- ------------------------------------------------------
-- 위 #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 의 월급여 획득
    );

- 단일 행 Sub-query -스칼라

  • 하나의 행을 반환
  • 반드시 단일 행 서브쿼리를 사용해야만 하는 경우:
    • 기본키(Primary Key)를 이용하는 경우
    • 그룹함수(MAX, MIN, SUM 등)를 이용하는 경우

(1) 평균 월급여보다 많은 월급을 받는 사원조회

-- 평균 급여를 먼저 구하기 위해, 단일 행 서브쿼리 및 그룹함수 AVG 사용
-- 따라서, 메인쿼리에서 사용가능한 연산자는 하나의 값과 비교하는 비교연산자임!

SELECT
    last_name,
    salary,
    ( SELECT avg(salary) FROM employees ) AS 평균급여
FROM
    employees
WHERE
    -- 메인쿼리: 단일행 서브쿼리가 사용되었으므로, 단일값과 비교가능한, 비교연산자 사용가능.
    salary >= ( 
        -- 단일 행 비상관 서브쿼리: 모든 사원의 평균 월급여 반환
        -- 메인쿼리로 결과값 전달
        SELECT
            avg(salary) 
        FROM
            employees
    );

(2) 100번 부서의 최대 월급여와 동일한 월급을 받는 사원조회

SELECT
    last_name,
    salary
FROM
    employees
WHERE
    -- 메인쿼리: 단일행 서브쿼리가 사용되었으므로, 단일값과 비교가능한, 비교연산자 사용가능
    salary = (
        -- 단일 행 비상관 서브쿼리: 100번 부서의 최대 월급여 반환
        -- 메인쿼리로 결과값 전달
        SELECT
            max(salary)
        FROM
            employees
        WHERE
            department_id = 100
    );

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

(4) 사원 Whalen 보다, 채용일자가 느린 사원조회

SELECT
    last_name,
    hire_date
FROM
    employees
WHERE
    -- 메인쿼리 1차 필터링: 단일행 서브쿼리가 사용되었으므로, 단일 값과 비교가능한, 비교연산자 사용가능
    hire_date > (
        -- 단일 행 비상관 서브쿼리: Whalen의 채용일자 반환
        -- 메인쿼리로 결과값 전달
        SELECT
            hire_date -- 현재시간과 가까워질수록 채용일이 늦은거 
        FROM
            employees
        WHERE
            last_name =  'Whalen'
    );

자바

pridecate

매개값 조사해 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
  • 위에 소스클래스를 위한 Student 클래스
@Getter
@AllArgsConstructor
public class Student {
	
	private String name;
	private String gender;
	private int point;

}

람다식의 파이프라인 디폴트 메서드

andThen() / compose()

  • 함수적 인터페이스가 가지고 있는 디폴트 메소드
  • 두 개의 함수적 인터페이스를 순차적으로 연결해 실행
  • 첫 번째 리턴값을 두 번째 매개값으로 제공해 최종 결과값 리턴
  • 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;
}
 

- 실행 클래스(andThen) (A > B > C 순서로 결합)

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

- 실행 클래스 (compose과 andThen 비교)

결과는 같음 어느것부터 시작하는지에 따름

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
profile
일단 흐자

0개의 댓글