디지털 컨버전스/Oracle

[Oracle] DQL 함수, length lengthb, dual 테이블, instr, substr, 날짜 관련 함수, 형 변환 함수, 조건 비교 함수, 그룹 함수

gimyeondong 2020. 3. 16. 09:18
  • SQL
  • DDL (Create / Drop / Alter)
  • DML (Insert / Select (DQL))
  • DCL (Grant / Revoke)
  • TCL (Rollback / Commit / Savepoint)

 

Select <column> from <table> where <조건> order by


-- 1. 근속년수가 10년 이상인 직원들의 이름, 급여, 근속연수 (소수점출력X)를 근속연수 오름차순으로 정렬하여 출력
-- 단, 여기서 급여는 50% 인상된 급여로 출력하시오
select emp_name 이름, salary*1.5 급여, floor((sysdate-hire_date)/365) 근속연수
from employee
where ((sysdate-hire_date)/365) > 10 
order by 3 ;
-- 2. 입사일이 99/01/01 ~ 10/01/01 인 사람 중에서
-- 급여가 2000000원 이하인 사람의
-- 이름, 주민번호, 이메일, 폰번호, 급여를 검색하세요
select emp_name 이름, emp_no 주민번호, email 이메일, salary 급여
from employee
where hire_date between '99/01/01' and '10/01/01' and salary <= 2000000;
--null value 함수 : 첫번째 인자값이 널이 아니면 그대로 반환, 널이면 두번째 인자값 반환
--출력할 대상 컬럼의 타입에 따라 변경할 타입을 정해줘야함 (bonus는 숫자형column)
select emp_name, nvl(bonus, 0) from employee;
-- 3. 급여가 2000000원 ~ 3000000원 인 여직원 중에서 4월 생일자를 검색하여
-- 이름, 주민번호, 급여, 부서코드를 주민번호 순으로(내림차순) 출력하세요.
-- 단, 부서코드가 null인 사람은 부서코드가 '없음'으로 출력하세요.
select emp_name 이름, emp_no 주민번호, salary 급여, nvl(dept_code, '없음') 부서코드
from employee
where (salary between 2000000 and 3000000) and emp_no like '_______2______' and emp_no like '__04__________'
order by 2 desc;
-- 4. 남자 사원 중 보너스가 없는 사원의 오늘까지의 근무일을 측정하여
-- 1000일 마다(소수점 제외) 급여의 10% 보너스를 계산하여
-- 이름, 특별 보너스 (계산 금액) 결과를 출력하세요.
-- 단, 이름 순으로 오름차순 정렬하여 출력하세요.
select emp_name 이름, salary*floor((sysdate-hire_date)/1000)*0.1 특별보너스
from employee
where emp_no like '_______1______' and bonus is null
order by 1 desc;

강사님 코드

-- 1. 근속년수가 10년 이상인 직원들의,
-- 이름, 급여, 근속년수 (소수점 출력 X)를 
-- 근속년수 오름차순으로 정렬하여 출력
-- 단 여기서 급여는 50% 인상된 급여로 출력하세요.

select emp_name,salary*1.5 as "인상 급여", floor((sysdate-hire_date)/365) as "근속년수"
from employee
where (sysdate-hire_date)/365 >= 10
order by 3;

-- 2. 입사일이 99/01/01 ~ 10/01/01 인 사람 중에서 
-- 급여가 2000000 원 이하인 사람의
-- 이름,주민번호,이메일,폰번호,급여를 검색하세요.

select emp_name,emp_no,email,phone,salary
from employee
where (hire_date between '99/01/01' and '10/01/01')
and salary <= 2000000;


-- 3. 급여가 2000000원 ~ 3000000원 인 여직원 중에서 4월 생일자를 검색하여 
-- 이름,주민번호,급여,부서코드를 주민번호 순으로(내림차순) 출력하세요.
-- 단, 부서코드가 null인 사람은 부서코드가 '없음' 으로 출력하세요.

select emp_name, emp_no, salary, nvl(dept_code,'없음')
from employee
where (salary between 2000000 and 3000000) and
emp_no like '___4__-2%' 
order by emp_no desc;


-- 4. 남자 사원 중 보너스가 없는 사원의 오늘까지 근무일을 측정하여 
-- 1000일 마다(소수점 제외) 급여의 10% 보너스를 계산하여 
-- 이름,특별 보너스 (계산 금액) 결과를 출력하세요.
-- 단, 이름 순으로 오름 차순 정렬하여 출력하세요.

select emp_name,floor((sysdate-hire_date)/1000)*(salary*0.1) as "특별 보너스" from employee
where emp_no like ('______-1%') and bonus is null
order by emp_name;

DQL 함수

-- 함수 ( function ) - 자바의 메서드와 동일한 동작 방식
-- 단일 행 함수 : 행 하나하나 마다 적용되는 함수
-- floor / nvl
select emp_name, nvl(dept_code, '부서없음')
from employee;

-- 그룹 함수 : 모든 행의 값을 추출해서 하나의 결과로 만들기
-- sum
select sum(salary) from employee;

length lengthb

-- length
select emp_name, length(emp_name), email, length(email)
    from employee;
-- lengthb : 바이트 길이
select emp_name, lengthb(emp_name), lengthb('AB')
    from employee;

dual 테이블

-- dual 테이블 : 오라클 사용자가 테스트 목적으로 사용하는 단일행 단일열 테이블 
-- 한번만 출력하고 싶다면 행이 하나인 테이블 필요
select 'Hello World' from employee;
select sysdate from dual;

instr

-- instr(String, STR, ?, ?) : 인자값 (타겟, 찾을문자열, 어디서부터, 몇번째것인지)

select instr('Hello World Hi High','H',1, 2) from dual;
-- 13 리턴

select instr('Hello World Hi High','H',2, 1) from dual;
-- 13 리턴

select instr('Hello World Hi High','H',2, 2) from dual;
-- 16 리턴

select instr('Hello World Hi High','H',2, 3) from dual;
-- 0 리턴 (찾지 못함)

select instr('Hello World Hi High','H',-1, 1) from dual;
-- 16 리턴 (세번째 인자값이 -1이면 뒤에서부터 찾기)

select instr('Hello World Hi High','H',-5, 1) from dual;
-- 13 리턴
--employee 테이블의 email에서 @문자의 위치를 출력하세요.
select email, instr(email,'@',1, 1) from employee;

substr

--substr

select
    substr('Hello Java Programmer',7,4)
from
    dual;
-- Java    

select
    substr('Hello Java Programmer',-10,7)
from
    dual;
-- Program

select
    substr('안녕 자바 프로그래머',4,2)
from
    dual;
-- 자바

-- 1. Employee테이블에서 직원들의 성씨만 중복없이 출력하세요
select
    distinct substr(emp_name,1,1)
from
    employee;
-- 2. Employee 테이블에서 남자직원의 사원번호, 사원명, 주민번호, 연봉을 출력하세요.
-- 주민번호의 뒷6자리는 *처리하세요
select
    emp_id 사원번호, emp_name 사원명, substr(emp_no,1,8)||'******' 주민번호, salary*12 연봉
from
    employee
where
    substr(emp_no,8,1)=1;

-- replace (대상, 찾을것, 변경할것)
select replace('Python Programmer','Python','Java') from dual;

숫자 관련 함수

-- abs ( absolute )
select abs(-10) from dual;
--mod ( 나머지연산 )

select mod(10,3) from dual;
-- 1

select mod(10,4) from dual;
-- 2
--round : 반올림함수

select round(126.456 , 3) from dual;
-- 126.456
-- 3번째 자리로 반올림 (cf. 3번째 자리에서 반올림 아님)

select round(126.456 , 2) from dual;
-- 126.46

select round(126.456 , 1) from dual;
-- 126.5

select round(126.456 , 0) from dual;
-- 126

select round(126.456 , -1) from dual;
-- 130

select round(126.456 , -2) from dual;
-- 100
-- floor : 버림함수
select floor(126.456) from dual;

-- trunc : 소수점 자리수에서 버림 함수
select trunc (126.456 , 1) from dual;
-- 126.4

select trunc (126.456 , 2) from dual;
-- 126.45

select trunc (126.456 , -1) from dual;
-- 120

select trunc (126.456 , 0) from dual;
-- 126

날짜 관련 함수

(예제 실행시 sysdate 20/03/16 (월) )

-- sysdate 현재 날짜를 반환하는 키워드
select sysdate from dual;
-- months_between : 두개의 시간값을 인자로 받아 두 시간 사이의 개월 수 반환
select emp_name, floor(months_between(sysdate, hire_date)) 근무개월
from employee;
-- 뺄셈으로는 일수가 나온다!
-- add_months : 특정 날짜에 개월수를 더해서 반환

select emp_name, add_months(hire_date,6)
from employee;

select add_months(sysdate, 50) from dual;
-- 24/05/16

-- 일수 구하기
select add_months(sysdate, 18)-sysdate 일 from dual;
-- 549
-- next_day : 인자로 전달받은 날짜에서 두번째 인자로 전달받은 요일 중, 가장 가까운 다음 요일을 출력
-- (숫자표현 : 1=일요일 ... 7=토요일)

select next_day(sysdate, '화요일') from dual;
-- 20/03/17
select next_day(sysdate, '월') from dual;
-- 20/03/23
select next_day(sysdate, 7) from dual;
-- 20/03/21
-- last_day : 첫번째 인자로 전달받은 날짜의 달에 해당하는 마지막 날짜 반환

select last_day(sysdate) from dual;
-- 20/03/31

select last_day(sysdate+16) from dual;
-- 20/04/30

-- 다음달의 마지막 날짜 구하기
select last_day(add_months(sysdate,1)) from dual;
-- 20/04/30
-- extract : 인자값으로 전달된 날짜에서 원하는 값을 추출

select extract (year from sysdate) from dual;
-- 2020
select extract (month from sysdate) from dual;
-- 3
select extract (day from sysdate) from dual;
-- 16

-- Employee 테이블에서 사원의 이름, 입사년, 입사월, 입사일, 년차를 출력하세요.
-- 각 입사날짜는 YYYY년 M월 D일로 출력하도록 하세요.
-- 년차 출력은 소수점일 경우 올림으로 하여 출력하세요 (28.144 -> 29년차)
-- (출력시 정렬은 입사년 기준으로 오름차순)

select  
    emp_name 이름,
    extract (year from hire_date) 입사년,
    extract (month from hire_date)입사월,
    ceil((sysdate - hire_date)/365)  년차
from employee;

 

-- 2. 특별 보너스를 지급하기 위하여 자료가 필요합니다.
-- 입사일을 기점으로 다음달 1일 부터 6개월 후를 출력하세요.
-- 이름, 입사일, 기준일, 기준일+6, 기준달(월)
-- ex) 90년2월6일 입사 -> 90년3월1일 부터 계산
-- ex) 90년2월26일 입사 -> 90년3월1일 부터 계산
-- ex) 97년12월1일 입사 -> 98년1월1일 부터 계산
-- 출력시 입사일 기준으로 정렬하세요.

select 
    emp_name as "이름", 
    hire_date as "입사일", 
    last_day(hire_date+1) as "기준일",
    add_months(last_day(hire_date+1),6) as "6개월 후",
    extract (month from add_months(last_day(hire_date+1),6)) as "기준달"
from employee
order by 2;

형 변환 함수

-- 현 변환 함수
-- to_char : 날짜 또는 숫자를 문자형으로 변경하는
-- date to char

select to_char(sysdate, 'yyyy@mm@dd') from dual;
--2020@03@16

select to_char(sysdate, 'yyyy/mm/dd/day') from dual;
--2020/03/16/월요일

select to_char(sysdate, 'yyyy/month/dd/day') from dual;
--2020/3월 /16/월요일

select to_char(sysdate, 'yyyy/mm/dd hh:mi:ss') from dual;
--2020/03/16 02:23:28

select to_char(sysdate, 'yyyy/mm/dd hh24:mi:ss') from dual;
--2020/03/16 14:24:28

select to_char(sysdate, 'yyyy/mm/dd hh12:mi:ss') from dual;
--2020/03/16 02:24:46 (뒤에12 안넣어도 디폴트)

select to_char(sysdate, 'yyyy/mm/dd hh시mi분ss초') from dual;
--01821. 00000 -  "date format not recognized"

select to_char(sysdate, 'yyyy/mm/dd hh"시"mi"분"ss"초"') from dual;
--2020/03/16 02시25분51초

select to_char(sysdate, 'yyyy/mm/dd(dy) hh"시"mi"분"ss"초"') from dual;
--2020/03/16(월) 02시27분18초

select emp_name, to_char(hire_date, 'yyyy/mm/dd(dy)') from employee;

문자로 바꾸기 (형식 주기)

-- number to char
select to_char(12345678, '000,000,000') from dual;
-- 012,345,678
select to_char(12345678, '999,999,999') from dual;
--  12,345,678
select to_char(12345678, '999,999') from dual;
--######## (형식이 부족하면 에러)

select to_char(12345678, 'L999,999,999') from dual;
--₩12,345,678 (local 통화)

select emp_name, to_char(salary, 'L999,999,999') from employee;

-- ltrim rtrim 왼쪽 공백지우기 / 오른쪽 공백 지우기
select emp_name, ltrim(to_char(salary, 'L999,999,999'),' ') from employee;

-- 1. employee 테이블에서 2000년도 이후에 입사한 사원의 사번, 이름, 입사일을 조회

select emp_id 사번,emp_name 이름, hire_date 입사일 
from employee
where hire_date > to_date(20000101,'YYYYMMDD')
order by 3;

--내가 푼 방식
select emp_id 사번,emp_name 이름, hire_date 입사일 
from employee
where to_char(hire_date,'yyyy')>=2000
order by 3;

조건 비교 함수

-- dcode
-- 매서드의 인자 부분이 가변 인자로 되어있다 : 인자개수 변함
select 
    emp_name ,  
    decode(substr(emp_no,8,1),1,'남',2,'여') 성별 
from employee;
-- case 
select
    emp_name, 
    case
        when substr(emp_no,8,1) = 1 then '남'
        when substr(emp_no,8,1) = 2 then '여'
        else '미정'
    end "성별" 
 from employee;
 
 -- 부등호 표기 가능 when substr(emp_no,8,1) >= 1 then '남'


 -- 60년대생 직원들 중, 65년생 이상의 직원은 60년생 후반
 -- 65년생 미만의 직원은 60년생 초반 이라고 출력하세요
 -- 이름 / 주빈번호 / 정보 출력
 
 select 
    emp_name 이름,
    emp_no 주민번호,
    case
        when substr(emp_no,1,2) >= 65 then '60년생 후반'
        when substr(emp_no,1,2) < 65 then '60년생 초반'
    end "정보"
from employee
where substr(emp_no,1,2) between 60 and 69;

그룹 함수

sum 합계 / avg 평균 / count 행의 개수

총합sum 합계

select ltrim(to_char(sum(salary), 'L999,999,999'),' ') 직원급여총합
from employee;


-- 1. 부서코드 D5 인 직원들의 급여 총합
select ltrim(to_char(sum(salary), 'L999,999,999'),' ') "D5부서 급여총계"
from employee
where dept_code ='D5';
-- 2. 여직원들의 급여 총합
select ltrim(to_char(sum(salary), 'L999,999,999'),' ') "여직원 급여총계"
from employee
where substr(emp_no,8,1) = 2;

avg 평균

-- avg 평균
select ltrim(to_char(avg(salary), 'L999,999,999'),' ')||'원' "직원급여평균"
from employee;

count 행의 개수

select count(emp_name) from employee;
-- 23
select count(dept_code) from employee;
-- 21 (null값 세지 않음)
select count(*) from employee;
-- 23 (행의 개수)
select count(*) from employee where dept_code='D5';
-- 6 (D5인 행수)
select count(distinct dept_code) from employee;
-- 6 (부서의 개수)

max / min - 촤대값, 최소값 함수

-- max / min - 촤대값, 최소값 함수
select max(salary), min(salary) from employee;

-- 1. 2020년4월15일까지 몇일 남았는지 출력
select floor(to_date(20200415,'YYYYMMDD')-sysdate)||'일' "4월15일까지" from dual;
-- 29일
-- 2. 2021년3월1일은 무슨 요일일까?
select to_char(to_date(20210301,'YYYYMMDD'),'day') "내년3월1일은" from dual;
-- 월요일
-- 3. 직원의 이름과 이메일 주소중 아이디 부분만 출력하시오

select 
    emp_name 이름, 
    substr(email,1,instr(email,'@',1)-1) 아이디
from employee;
-- 4. 70년대생 직원들의 급여총합
select ltrim(to_char(sum(salary), 'L999,999,999'),' ')  "70년대생 급여총계" 
from employee  
where substr(emp_no,1,2) between 70 and 79;
--₩21,316,240
-- 5. 60년생의 직원명과 년생, 보너스 값을 출력하시오
-- 그떄 보너스 값이 null인 경우에는 0이라고 출력 되게 만드시오
select 
    emp_name 직원명, 
    substr(emp_no,1,2) 년생, 
    case 
        when bonus is null then 0
        when bonus is not null then bonus
    end  "보너스"
from employee  
where substr(emp_no,1,2) between 60 and 69;

DDL 위주로 공부

서술형 / 문제해결 시나리오