SQL

oracle19c - 연습 (HR 05.06)

jomericano 2022. 5. 11. 20:27
sequence_sysdate



-- crud 예제
-- 커뮤니티 게시판을 위한 테이블 작성
-- 회원테이블 member 테이블 (회원번호, 아이디, 비밀번호, 이메일, 이름, 가입일)

create table MEMBER (
    mbno      number   generated as identity,
    userid    varchar2(18)  not null,
    passwd    varchar2(18)  not null ,
    email     varchar2(100) not null ,
    name      varchar2(15)  not null ,
    regdate   date   default  sysdate + 9/24,
    -- regdate   date   default  sysdate,  --서버시간으로 맞지 않음
    constraint mbpk primary key (mbno)  );






-- 게시판 ( 글번호, 제목, 작성자, 작성일, 조회수, 본문)
create table BOARD (
    -- bdno        number,
    -- bdno        number default bd_seq.nextval,  --시퀀스객체를 만들어야하는 불편함이 있음
    bdno        number  generated as identity,    -- 오라클 12 c 부터 지원
    title       varchar2(300)   not null ,
    mbno        number,
    regdate     date    default  sysdate + 9/24,
    reads       number  default 0 ,
    contents    clob ,
    constraint bdpk primary key (bdno));






  alter table  BOARD
add constraint bd_fk
foreign key (mbno) references MEMBER(mbno);




-- 회원가입
insert into MEMBER  (userid,passwd,email, name)
values ('abc123', '987xyz', 'abc123@987xyz.com', '혜교');

insert into BOARD (title, mbno, contents)
values ('테스트', 1, '제곧내');




-- 자동증가 확인
select *
from MEMBER;




-- 서버 시간 보완
select sysdate from dual;  --서버 시스템 시간
alter session set time_zone = 'asia/seoul';  -- 시간대 변경
select current_date from dual;  --현지시간
select localtimestamp from dual;  --현지시간
select current_timestamp from dual;  --현지시간 (!)

select sysdate from dual;  -- 서버시간 반영

select sysdate +1 from dual ;  -- 현재시간 날짜에 1 day 추가
select sysdate +1/24 from dual ;  -- 현재시간 날짜에 1 hour 추가
select sysdate +9/24 from dual ;  -- 현재시간 날짜에 9 hour 추가



-- 자동증가번호 설정 : sequence
-- 순차적으로 증가하는 순번을 반환하는 데이터베이스 객체
-- 보통 pk컬럼에 중복값이 삽입되는 것을 방지하기 위해 사용

-- create sequence 이름 ;      --   자동증가(기업체에서 자주 사용)
-- create sequence 이름  start with 시작번호 increment by 증가값 ;
-- create sequence 이름  start with 시작번호 increment by 증가값
-- nocycle nocache;

create sequence mb_seq;
create sequence bd_seq;








-- sequence를 이용한 데이터 삽입
-- pk컬럼 삽입시 '시퀀스 이름. nextval' 사용
insert into BOARD(bdno, title, mbno, contents)
values (bd_seq.nextval,'테스트테스트',1,'제곧네~');

select * from BOARD;

--오라클에서 시퀀스객체 값을 자동으로 컬럼에 입력하려면?
-- orecle 11g이하는 트리거 이용
-- orecle 12c이상은 default 제약조건에 시퀀스를 지정하거나 generated by default as identify 사용
rollup,cube

 --고급 분석함수 : rollup
 -- 그룹함수로 집계된 결과들에서 소계, 합계를 쉽게 구하기위해 사용

 -- 고객들의 등급별 마일리지 합계조회
select GRADE, sum(MILEGE)
from "Customers"
group by GRADE;

 -- 사원들의 부서별, 직책별 연봉 총합 조회;
select DEPTID, JOBID, sum(sal) from emp
group by DEPTID, JOBID
order by DEPTID;

 -- rollup (기준컬럼들 ... )
select DEPTID, JOBID, sum(sal) from emp
group by rollup((DEPTID, JOBID))       -- 각각 다 구해줌
order by DEPTID;

 -- rollup ( (기준컬럼들 ... ) )  group by랑 별 차이없음
select DEPTID, JOBID, sum(sal) from emp
group by rollup((DEPTID, JOBID))       -- 직책의 전체 연봉합
order by DEPTID;




 --고급 분석함수 : cube
 --rollup 함수에 비해 좀더 다양한 집계 결과를 표시
select  JOBID, sum(sal) 연봉총합 from emp
group by cube( JOBID );                -- 상단에 전체 연봉합이 표시됨.



 -- 사원들의 부서별, 직책별 연봉 총합 조회;
select DEPTID, JOBID, sum(sal) 연봉총합 from emp
group by cube(DEPTID, JOBID);           -- 처음에 null인 값들의 연봉합이 표시,
                                        -- 그 다음에 직책별 연봉합이 표시
                                        -- 마지막으로 부서별 연봉합과 부서별 직책별 연봉합이 표시

 -- having절을 이용해서 부분별 소계를 표시
select DEPTID, JOBID, sum(sal) 연봉총합 from emp
group by cube(DEPTID, JOBID)
having grouping_id(DEPTID, JOBID)=1;     -- 부서별 총합

 -- having절을 이용해서 부분별 소계를 표시
select DEPTID, JOBID, sum(sal) 연봉총합 from emp
group by cube(DEPTID, JOBID)
having grouping_id(DEPTID, JOBID)=2;    -- 직책별 총합

 -- having절을 이용해서 부분별 소계를 표시
select DEPTID, JOBID, sum(sal) 연봉총합 from emp
group by cube(DEPTID, JOBID)
having grouping_id(DEPTID, JOBID)=3;    -- 모든 연봉 총합






-- 사원 테이블에서 사원 이름을 소문자로 출력하세요
select lower (LAST_NAME) from EMPLOYEES;




-- 사원 테이블에서 사원 이름의 첫글자만 대문자로 출력하세요.
select substr(upper (LAST_NAME),1,1) from EMPLOYEES;



-- 사원 테이블에서 사원 이름의 길이를 출력하세요.
select length(LAST_NAME) from EMPLOYEES;

-- 사원 테이블에서 사원이름과 이름에 A가 몇번째 있는지 출력하세요.
select LAST_NAME, instr(LAST_NAME,'a',1) from EMPLOYEES;
select LAST_NAME, instr(upper(LAST_NAME),'A') from EMPLOYEES;


-- 사원 테이블에서 사원이름의 세번째 자리가 R인 사원의 정보를
-- 출력하세요.
select * from EMPLOYEES where substr(LAST_NAME, 3,1 )='r';

-- 사원 테이블에서 이름의 끝자리가
-- N으로 끝나는 사원의 정보를 출력하세요.
SELECT * FROM EMPLOYEES WHERE INSTR(LAST_NAME,'n')=LENGTH(LAST_NAME);

-- n이 처음나오는위치가 이름길이인 사람
select FIRST_NAME,  substr(first_name,-1,1) from EMPLOYEES
where substr(upper(first_name),-1,1) = 'n';
-- n이 처음나오는위치가 이름길이인 사람



-- 사원들의 급여가 평균보다 큰 경우 '평균급여이상'이라 출력하고
-- 아닌 경우 '평균급여이하' 라고 출력하세요
select SALARY, round(avg(SALARY)) over (  ) ) 평균급여,
      case when salary >= (select round(avg(sal)) from employee) then '평균급여이상'
           when salary >= (select round(avg(sal)) from employee) then '평균급여이하'  end 급여평가
from employee;


select sal,(select round(avg(sal)) from emp) 평균급여,
      case when sal >=(select round(avg(sal)) from emp) then '평균급여이상'
           when sal >= (select round(avg(sal)) from emp) then '평균급여이하'  end 급여평가
from emp;







-- 사원의 급여에 대해 평균을 계산하고
-- 정수로 변환해서 출력하세요 (cast이용)
select round(           cast(   (    avg( SALARY )    )   as number)     )  from EMPLOYEES;
select round(           cast(   (    avg( SALARY )    )  as decimal(5,0)     )  )from EMPLOYEES;
select cast(avg(SALARY) as decimal) from EMPLOYEES;



-- 사원들을 입사일자가 빠른 순으로
-- 정렬한 뒤 본인보다 입사일자가 빠른
-- 사원의 급여를 본인의 급여와 함께 출력하세요   윈도우함수 : lag, lead 사용
select FIRST_NAME, HIRE_DATE, SALARY,
       lag(SALARY)  over (order by HIRE_DATE ) 이전사원급여,
       lead(SALARY) over (order by HIRE_DATE ) 이후사원급여
from EMPLOYEES  order by HIRE_DATE;




-- AND나 BETWEEN을 사용하지 않고
-- 2002 년도에 입사한 직원의 이름과
-- 월급을 출력하세요.
select * from EMPLOYEES where substr(HIRE_DATE,0,4) = '2002';



-- 사원 테이블에서 사원의 이름이
-- 5글자인 사원의 이름을 첫글자만 대문자로 출력하세요.
select initcap(LAST_NAME) from EMPLOYEES where length(LAST_NAME)=5;

-- and나 between을 사용하지않고 2002년도 입사한 직원의 이름과 월급
select FIRST_NAME, HIRE_DATE from EMPLOYEES where substr(HIRE_DATE, 3, 2) = '02';




-- 사원 테이블에서 이름과 입사일자
-- 그리고 현재날까지의 경과일을 산출하세요
-- (소숫점을 빼버리고 해당이름을 경과일로 바꾸세요) (datediff이용 mariadb)
select FIRST_NAME, HIRE_DATE,
       concat(to_char(floor(sysdate - to_date(HIRE_DATE)),'9,999'), ' 일') 경과일
from EMPLOYEES;

select  concat(to_char(floor(sysdate - to_date(hire_date)), '9,999'), '일' ) from EMPLOYEES;


-- 이전문제에서 경과일을 개월수로 바꿔서
-- 산출하세요. 소숫점을 빼버리고
-- 해당이름을 경과개월수로 바꾸세요 (timestampdiff이용)
select FIRST_NAME, HIRE_DATE,
       concat(to_char(floor(sysdate - to_date(HIRE_DATE))*1/30,'9,999'), ' 개월') 경과개월수
from EMPLOYEES;


-- 사원 테이블에서 입사후 6개월이
-- 지난날짜 바로 다음 일요일을 구하세요.

select FIRST_NAME,HIRE_DATE, to_date(HIRE_DATE,'yyyy-mm-dd')+ 365/2 "6개월",
add_months(HIRE_DATE,6) "6개월후",
next_day(add_months(HIRE_DATE,6), '일') "6개월후다음일요일" from EMPLOYEES;

-- 교육시작일이 2020-11-02인 경우,
-- 5개월(18주)이 지난후 돌아오는 첫번째 금요일이
-- 언제인지 조회하세요 (5개월(18주) : 2021-03-08)
select '2020-11-02' 교육시작일, next_day(add_months('2020-11-02', 5), '금') ,
       next_day(to_date('2020-11-02') +(18*7), '금')  from dual;

-- 교육시작일이 2020-11-02인 경우,
-- 131일이 지난후 돌아오는 첫번째 금요일이
-- 언제인지 조회하세요 (131일후 : 2021-03-11)
select '2020-11-02' 교육시작일, next_day(to_date('2020-11-02') + 131,'금')  from dual;



-- 사원 테이블에서 입사후
-- 첫 휴일(일요일)은 언제일지 구하세요
select FIRST_NAME,HIRE_DATE, next_day(HIRE_DATE, '일') 입사후첫휴일 from EMPLOYEES;


-- 오늘날짜를 "xx년 xx월 xx일" 형식으로 출력하세요
select to_char(sysdate, 'yyyy"년" mm"월" dd"일"') 오늘날짜 from dual;

-- 지금 현재 '몇시 몇분'인지 출력하세요.
-- AWS RDS의 시간은 미국 기준
-- 한국 기준시로 변경하고 싶다면 서버설정변경(time-zone) 필요
-- 한국은 UTC 기준 9시간 추가 : KST = UTC + 9
select to_char(sysdate + 9/24, 'am hh"시" mi"분"') 오늘시간 from dual;


-- 이번 년도 12월 31일까지 몇일이
-- 남았는지 출력하세요. (datediff이용)
select floor(to_date('2022-12-31' - 'yyyy-mm-dd') - sysdate) 연말까지남은일수 from dual;


-- 사원들의 입사일에서
-- 입사 년도와 입사 달을 조회하세요
select HIRE_DATE, to_char(to_date(HIRE_DATE), 'yyyy"년" mm"월" ') 입사년월
 from EMPLOYEES;
-- 9월에 입사한 사원을 조회하세요
select FIRST_NAME, HIRE_DATE from EMPLOYEES where substr(HIRE_DATE,6,2)='09';
select FIRST_NAME, HIRE_DATE from EMPLOYEES where instr(HIRE_DATE, '09',6)=6;

select instr('2009-09-01', '09',6) from dual;

-- 사원들의 입사일을 출력하되,
-- 요일까지 함께 조회하세요
select FIRST_NAME, to_char(to_date(HIRE_DATE), 'yyyy-mm-dd day') 입사일 from EMPLOYEES;

-- 사원들의 급여를 통화 기호를 앞에 붙이고
-- 천 단위마다 콤마를 붙여서 조회하세요
-- format(값, 반올림자릿수) : 숫자에 컴마를 붙여 출력
select FIRST_NAME, SALARY,
       to_char(SALARY, '$99,999') "꾸며진급여" ,
       to_char(SALARY*1267, 'l999,999,999') "환율급여" from EMPLOYEES;



-- 사원들의 급여를 10자리로 출력하되
-- 자릿수가 남는 경우 빈칸으로 채워서 조회하세요
-- _____12345
select FIRST_NAME, SALARY,
       to_char(SALARY, '9999999999') "꾸며진급여",
       to_char(SALARY, '0000099999') "0으로채움",
       to_char(SALARY, 'FM9999999999') "공백제거"
from EMPLOYEES;


-- 각 사원들의 근무한 개월 수를 현재를
-- 기준으로 구하세요 (timestampdiff이용)



-- 각 사원들의 입사일에서
-- 4개월을 추가한 날짜를 조회하세요
select HIRE_DATE, add_months(HIRE_DATE,4) "입사일+4개월" from EMPLOYEES;



-- 각 사원들의 입사한 달의 마지막 날을
-- 조회하세요 (last_day이용)
select HIRE_DATE, last_day(HIRE_DATE)
from EMPLOYEES;




-- 매니저와 그 매니저를 상사로 두고 있는 사원들의 연봉의 총합을 조회  (  매니저와 매니저상사사원의 연봉의 합)
 select coalesce(MANAGER_ID,SALARY )  from EMPLOYEES;

select FIRST_NAME, EMPLOYEE_ID, SALARY, COMMISSION_PCT,
         coalesce((COMMISSION_PCT+1)*SALARY, SALARY)  --null이아니면 앞, null이면 뒤
    총급여 from EMPLOYEES;

select fname, EMPID, EMGRID,
       -- sum(sal) over () 연봉총합,
       sum(sal) over (partition by EMGRID order by SAL)  매니저와사원연봉총합
from emp;


-- 사원들의 연봉이 높은 순서와 직책별로 높은 순으로 조회
SELECT FIRST_NAME, SALARY, JOB_ID,
       dense_RANK() over (order by SALARY desc ) SAL,
       dense_RANK() over (partition by JOB_ID order by SALARY desc) 직책별
FROM EMPLOYEES;




-- 사원들을 입사일자가 빠른 순으로 정렬한 뒤
-- 본인과 이전/이후 사원간의 입사일의 차이를 조회하세요
select FIRST_NAME, HIRE_DATE ,
       lag  (HIRE_DATE) over ( order by HIRE_DATE) 이전입사일,
       lead (HIRE_DATE) over ( order by HIRE_DATE) 이후입사일,
       abs( to_date(HIRE_DATE) - lag(to_date(HIRE_DATE)) over ( order by HIRE_DATE) ) 이전일차이,
       abs( to_date(HIRE_DATE) - lead(to_date(HIRE_DATE)) over ( order by HIRE_DATE) ) 이후입사일차이

from EMPLOYEES order by HIRE_DATE;

select name, MILEGE,
       abs(MILEGE - lead(MILEGE) over ( order by USERID)) 이후마일리지차이
from "Customers";


-- HR 부서에서는 신규 프로젝트의 성공으로 해당하는 각 업무 자들에 대한 급여 인상안을 결정하고,
-- 다음과 같이 업무 별 급여 인상에 대해 적용하고자 한다.
-- 현재 107명의 사원은 19개의 업무에 소속되어 근무 중이다.
-- (Distinct job_id) 이 중 5개의 업무 자들에 대한 급여 인상이 각각 결정되었고,
-- 나머지 업무에 대해서는 인상이 동결되었다 (107행).
-- HR_REP(10%), MK_REP(12%), PR_REP(15%), SA_REP(18%), IT_PROG(20%)


select EMPLOYEE_ID, LAST_NAME, JOB_ID, SALARY,
  case JOB_ID when 'HR_REP' then SALARY * 1.1
             when  'MK_REP' then SALARY * 1.12
             when  'PR_REP' then SALARY * 1.15
             when 'SA_REP'  then SALARY * 1.18
             when 'IT_PROG' then SALARY * 1.20
             else salary    end  "new salary"
from employees;



select EMPLOYEE_ID, LAST_NAME, JOB_ID, SALARY,
       decode(JOB_ID, 'HR_REP'  , SALARY * 1.1 ,    --비교연산자에는 case ''when''then''
                      'MK_REP'  , SALARY * 1.12,
                      'PR_REP'  , SALARY * 1.15,
                      'SA_REP'  , SALARY * 1.18,
                      'IT_PROG' , SALARY * 1.20,  SALARY  ) newsal
from EMPLOYEES;