▶오늘의 SQL 주요 포인트
▶형 변환 함수
★to_char : 날짜 값을 문자로 형 변환하는 함수, data -> char
to_char(sysdate, '형식')
yyyy - 세기년도
yy- 년도
year - 세기 년도 (영어로)
mm - 월
month - 월 + "월"표시까지
mon - 월 + "월"표시까지
ddd - 올해 1년 중 며칠 지났는지
dd 이번달 며칠 지났는지
d - 이번 주 몇 일 지났는지 (일요일이 1 월요일이 2~~ 토요일이 7 오름차순으로 할 때)
day - 요일
dy - 요일 약어
ww- 몇 주 지났는지
iw - ios 기준에서 몇 주 지났는지
w - 그 달의 주
q - 분기
ddth - 서수단위(dd대신 다른 형식들 넣기 가능)
ddsp - 스펠링
ddthsp - 서수단위스펠링
fm -선행되는 0을 제거해줌(fmmm : 03에서 3으로 바꿔줌)
★to_number(문자 숫자, 숫자 모델 요소(생략)) 문자 -> 숫자
★to_date(문자 날짜, 날짜포맷모델요소) : 문자날짜 -> 날짜
▶NULL관련 함수
★nvl(컬럼, 리턴할 값)
- null값을 실제값으로 리턴하는 함수
- nvl함수는 입력되는 인수값들의 데이터 타입이 일치해야 한다.
★nvl2(exp1,exp2,exp3)
-첫 번째 exp1이 null 아니면 exp2를 수행하고 첫 번째 exp1이 null이면 exp3를 수행한다.
-exp2,exp3의 데이터 타입이 일치해야 한다.
★coalesce(exp1,exp2,exp3,.....expn)
- 첫 번째 exp1이 null이면 두 번째 exp2를 수행하고 두 번째 표현식도 null이면 exp3을 수행한다.
즉 null이 발생하지 않을 때까지 표현식을 수행하는 기능
★nullif(exp1,exp2)
-두 표현식을 비교해서 같으면 null을 리턴하고 같지 않으면 첫 번째 표현식을 리턴한다.
▶조건제어문
★decode 함수는 기준값과 비교 값을 같다(=) 비교 연산자만 사용한다.
decode(기준값,
비교 값 1, 참값 1,
비교 값 2, 참값 2,
비교 값 3, 참값 3,......
기준값)
★case 표현식 : 기준값과 비교 값의 대해서 모든 비교연산자를 사용할 수 있다.
case 기준값 = 비교값
when 비교 값 1 then 참값 1
when 비교 값 2 then 참값 2
when 비교 값 3 then 참값 3
...
else 기준값
end
▶강사님의 주요 말씀
-문제에는 답이 없고 다양한 답이 나올 수 있다. 문제 해결 능력 키우기 즉 계속 생각하고 다양한 방법으로도 풀어보자
-실무에서 바로 사용할 수 있도록 무한 반복학습을 통해 훈련하자
[문제 20]
주민번호_1 주민번호_2
--------------- ------------------
210101-1234567 210101-1******
select '210101-1234567' 주민번호_1,
rpad(substr('210101-1234567',1,8),14,'*') "주민번호_2",
--rpad(substr('210101-1234567',1,instr('210101-1234567','-',1,1)+1),length('210101-1234567'),'*') "주민번호_2"
from dual; --다른 방법들도 해보기 정답은 없다(이건 강사님 답)
[문제 21] 전화번호 가운데 4자리 부분을 아래 화면과 같이 출력해주세요.
전화번호_1 전화번호_2
---------------- ------------------
010-1000-1004 010-****-1004
SELECT '010-1000-1004' "전화번호_1",
concat(rpad(substr('010-1000-1004',1,4),8,'*')
,substr('010-1000-1004',-5,5))
FROM dual;
[문제 22] 메일주소를 아래화면과 같이 출력해주세요.
EMAIL_1 EMAIL_2
------------------ -------------------
james@itwill.com j****@itwill.com
SELECT 'james@itwill.com' "EMAIL_1",
concat(concat(substr('james@itwill.com',1,1),
rpad('*',instr('james@itwill.com','@',1,1)-2,'*')),
substr('james@itwill.com',instr('james@itwill.com','@',1,1)))
FROM dual;
★형변환 함수
★to_char : 날짜값을 문자로 형 변환하는 함수, data -> char
SELECT * FROM nls_session_parameters;
SELECT sysdate,
to_char(sysdate, 'yyyy-mm-dd hh24:mi:ss.sssss'),
to_char(sysdate, 'yyyymmdd hh24miss.sssss'),
to_char(sysdate, 'yyyy"년도" year month mon mm'),
to_char(sysdate, 'ddd dd d'),
to_char(sysdate, 'day dy'),
to_char(sysdate, 'ww iw w')
FROM dual;
SELECT sysdate,
to_char(sysdate,'q'),
to_char(sysdate,'q"분기"'), --리터럴문자로 넣을 때 큰따옴표 필수
to_char(sysdate,'q') || '분기',
concat( to_char(sysdate,'q'),'분기'),
to_char(sysdate,'dd ddth ddsp ddthsp')
FROM dual;
[문제23] 사원들의 사원번호, 입사한 요일을 출력하세요. 단 요일을 오름차순 정렬해주세요.
SELECT employee_id,hire_date, to_char(hire_date,'day')
FROM employees
ORDER BY to_char(hire_date,'d'); --요일 별로 하기 위해서는 d(일요일기준 일월화수목금토)
SELECT employee_id,hire_date, to_char(hire_date,'day')
FROM employees
ORDER BY to_char(hire_date-1,'d'); --월요일부터(월화수목금토)
[문제 24] employees(사원) 테이블에서 일요일에 입사한 사원의 정보를 조회하세요.
SELECT *
FROM employees
WHERE to_char(hire_date,'day') = '일요일';
SELECT *
FROM employees
WHERE to_char(hire_date,'dy') = '일';
SELECT *
FROM employees
WHERE to_char(hire_date,'d') = '1';
[문제 25] 오늘 날짜를 "2021년 12월 21일 화요일" 출력해주세요.
SELECT to_char(sysdate, 'yyyy"년" mm"월" dd"일" day"') --리터럴문자는 날짜 포맷 안에서 ""(큰따옴표 필수) 안에 작성
FROM dual;
SELECT to_char(sysdate, 'yyyy"년" month dd"일" day"'),
to_char(sysdate,'dl') --dl은 'yyyy"년" month dd"일" day'이 표시 형식을 간단히 표현한 것
FROM dual;
[문제 26] 사원의 employees(사원) 테이블에 있는 last_name, hire_date 및 근무 6 개월 후 첫 번째 월요일에 해당하는 급여 협상 날짜를 표시합니다.
열 레이블을 REVIEW로 지정합니다.
날짜는 "월요일, the Second of 4, 2007"과 유사한 형식으로 나타나도록 지정합니다.
SELECT last_name, hire_date,
to_char(next_day(add_months(hire_date,6), '월요일'), 'day", the" Ddspth "of" mm, yyyy') REVIEW
--영어 날짜 서수 표기에서 dd -> Dd 하게 되면 맨 앞 글자가 대문자가 됨
FROM employees;
SELECT to_char(sysdate,'fmhh hh24 am')
FROM dual;
★참고
to_char(날짜, '날짜모델요소') : 날짜 -> 문자
to_char(숫자, '숫자모델요소') : 숫자 -> 문자
객체지향 프로그램
overloading
-함수 이름은 같지만 인수값으로 어떤 자료형이 들어오느냐에 따라 프로그램은 틀리게 수행하는 기능
-함수이름은 같지만 전혀 다른 함수들이다.
SELECT employee_id, salary,
to_char(salary, '999,999.00'),--숫자 한자리 한자리를 9로 표현, 9자리의 값이 없으면 아무 값도 채우지 않는다.
to_char(salary, '000,999.00'), --0자리에 숫자가 없으면 0으로 표현
to_char(salary, '999'), -- 표현해야 할 자릿수가 안 맞으면 #으로 출력됨
to_char(salary, '$9999,999.00'),
to_char(salary, 'l9999,999.00'), -- l(엘) : 현재 세션을 맺는 지역의 통화 부호를 표현
to_char(salary, 'l9999g999d00') --천 단위 컴마(,) 대신 g, 소수점(.) 대신 d를 사용하기도 함
FROM employees;
alter session set nls_territory = france;
alter session set nls_language = french;
SELECT * FROM nls_session_parameters;
alter session set nls_territory = korea;
alter session set nls_language = korean;
SELECT employee_id,
to_char(hire_date,'yyyy month dd day year'),
to_char(salary, 'l999g999d00') -- 천단위는g 소수점은 d
FROM employees;
SELECT
to_char(-1000, '9999'),
to_char(-1000, '9999pr'), --음수일 경우 <>로 묶는다.
to_char(-1000, '9999mi'), --음수를 뒤에 표현한다.
to_char(+1000, 's9999') -- 부호를 표현한다.
FROM dual;
암시적으로 형 변환을 해준다.
SELECT '1' + 1
FROM dual;
to_number(문자 숫자, 숫자 모델 요소(생략)) : 문자 -> 숫자
SELECT to_number('1', '9') + 1,
to_number('1') + 1 -- 숫자모델요소 생략 가능
FROM dual;
SELECT sysdate + 1, sysdate + to_number('1')
FROM dual;
[문제 27] 짝수 달에 입사한 사원들의 정보를 출력해주세요.
SELECT *
from employees
WHERE mod(to_number(to_char(hire_date,'mm')),2) = 0;
[문제 28] 2006년도에 홀수달에 입사한 사원들의 정보를 출력해주세요.
SELECT * --내가 풀이 한 코드 (안 좋은 코드)
FROM employees
WHERE to_char(hire_date, 'yyyy') = '2006'
AND mod(to_number(to_char(hire_date,'mm')),2) =1;
--to_number로 숫자형으로 변형하지 않더라도 암시적으로 형이 바뀌어서 수행됨
--하지만 명시적으로 사용한다.
SELECT * --안정적인 코드
from employees
WHERE mod(to_number(to_char(hire_date,'mm')),2) != 0
and hire_date >= '2006/01/01'
and hire_date <='2006/12/31'; -- = WHERE hire_date between '2006/01/01' and '2006/12/31';
/* 악성프로그램
SELECT *
FROM employees
WHERE HIRE_DATE LIKE '06%';
--내부적으로 to_char(hire_date) like '06%';를 수행함 : 여기서 문제점은 만약에 hire_date가 인덱스가 생성되어 있는 컬럼일 경우 인덱스 스캔이 아닌 테이블 full scan이 수행된다.
--like연산자는 문자 패턴을 찾는 연산자
--hire_date가 문자 칼럼이 아니면 암시적으로 형을 변환해서 수행
--대소문자나 형이 변환되는 것(데이터 타입이 바뀌는 것)은 배제하자!
--파이썬이나 R에서는 상관없음
SELECT *
FROM employees
WHERE to_char(hire_date, 'yyyy') = '2006'
-- 같은 문제점
*/
SELECT * FROM nls_session_parameters;
ALTER session set nls_territory = america;
alter session set nls_language = american;
SELECT * --지역에 따라 날짜 형식은 민감
from employees
WHERE hire_date >= '2006/01/01'--문자형임(내부적으로 돌아감 to_date가)
and hire_date <='2006/12/31';
-현재 아메리카로 세션을 변경해서 위에 예제에 에러가 뜬다.
-'2006/01/01은 한국 전용 날짜이며 문자형으로 아메리카 지역에서는 출력되지 않는다.
SELECT * --지역에 따라 날짜 형식은 민감
from employees
WHERE hire_date >= '01-JAN-06'
and hire_date <='31-DEC-2006';
- 현재 아메리카로 세션을 변경해서 위에 예제가 출력된다.
★to_date(문자 날짜, 날짜포맷모델요소) : 문자날짜 -> 날짜
SELECT *
from employees
WHERE hire_date >= to_date('2006/01/01', 'yyyy/mm/dd') --명시적으로 날짜 표기할 때 to_date함수를 쓰는 습관을 가지자 이렇게 하면 지역에 상관없이 돌아감
and hire_date <= to_date('2006/12/31 23:59:59', 'yyyy/mm/dd hh24:mi:ss'); --주의할 점 2006/1월/1일 00시부터는 맞지만 2006/12월 31일도 00시까지이므로 이렇게 표현
SELECT *
from employees
WHERE hire_date >= to_date('2006/01/01', 'yyyy/mm/dd') --명시적으로 쓰는 습관을 가지자 이렇게 하면 지역에 상관없이 돌아감
and hire_date < to_date('2007/01/01', 'yyyy/mm/dd');-- 이런 방식으로 표현할 수 있는데 대신 between and 연산자 사용불가
▶NULL관련 함수
★nvl
- null값을 실제값으로 리턴하는 함수
- nvl함수는 입력되는 인수값들의 데이터 타입이 일치해야 한다.
/* nvl 구조
if exp1 is null then
return exp2
else
return exp1
end if;
*/
desc employees
SELECT employee_id, salary, commission_pct,
((salary * 12) + (salary * 12 * commission_pct)) ann_sal,
((salary * 12) + (salary * 12 * nvl(commission_pct,0))) ann_sal2
FROM employees;
SELECT nvl(commission_pct,'no comm') --형의 불일치 때문에 오류가 남 commission_pct는 숫자, 'no comm'은 문자
FROM employees;
SELECT nvl(to_char(commission_pct),'no comm')
FROM employees;
--commission_pct의 타입을 char로 변환하여 두 인수의 타입이 일치하면 됨
★nvl2(exp1,exp2,exp3)
-첫 번째 exp1이 null 아니면 exp2를 수행하고 첫 번째 exp1이 null이면 exp3를 수행한다.
-exp2, exp3의 데이터 타입이 일치해야 한다.
/* nvl2의 구조
if exp1 is not null then
exp2
else
exp3
end if;
*/
SELECT employee_id, salary, commission_pct,
nvl2(commission_pct,(salary*12) + (salary*12*commission_pct), salary*12) ann_sal
FROM employees;
SELECT employee_id,salary,commission_pct,
nvl2(commission_pct,to_char(salary*12), 'no comm') ann_sal
FROM employees;
--salary는 숫자형이고 'no comm'은 문자형이므로 둘 중 하나를 형 변환해서 같은 타입으로 만들어 주어야 한다. 따라서 to_char함수를 사용하여 salary*12를 문자형으로 만들어서 nvl2함수를 수행했다.
★coalesce(exp1, exp2, exp3,..... expn)
- 첫 번째 exp1이 null이면 두 번째 exp2를 수행하고 두 번째 표현식도 null이면 exp3을 수행한다.
! 즉 null이 발생하지 않을 때까지 표현식을 수행하는 기능
SELECT employee_id,
coalesce((salary*12) + (salary*12*commission_pct), salary*12,0)
FROM employees;
★nullif(exp1, exp2)
-두 표현식을 비교해서 같으면 null을 리턴하고 같지 않으면 첫 번째 표현식을 리턴한다.
/* nullif 구조
if exp1 = exp2 then
null
else
exp1
end if;
*/
SELECT employee_id, last_name, first_name,
nullif(length(last_name), length(first_name)) nullif1,
nullif(length(first_name), length(last_name)) nullif2
FROM employees;
--nullif1열은 첫 번째 인수인 last_name의 길이와 두 번째 first_name의 길이가 같으면 null 리턴, 다르면 첫 번째 인수 last_name의 길이를 출력. nullif2는 반대
▶조건 제어문
if를 사용할 수 있도록 decode함수, case 표현식을 제공한다.
decode
if 기준값 = 비교 값 1 then
참값 1
else 기준값 = 비교 값 2 then
참값 2
else if 기준값= 비교 값 3 then
참값 3
else
기준값
end if;
★decode 함수는 기준값과 비교 값을 같다(=) 비교 연산자만 사용한다.
decode(기준값,
비교 값 1, 참값 1,
비교 값 2, 참값 2,
비교 값 3, 참값 3,......
기준값)
/* 일반적인 if문
if job_id = 'IT_PROG' then
salary * 1.1
else if job_id = 'SY_CLERK' then
salary * 1.2
else if job_id = 'SA_REP' then
salary *1.3
else
salary
end if;
*/
위의 if문을 decode로 출력하기
SELECT employee_id, job_id,
decode(job_id, 'IT_PROG', salary *1.1,
'ST_CLERK', salary * 1.2,
'SA_REP', salary * 1.3,
salary) rewised_salary
from employees;
★case 표현식 : 기준값과 비교 값의 대해서 decode와는 다르게 모든 비교 연산자를 사용할 수 있다.
※case문 안에서 ', '(컴마)를 사용하지 않도록 주의
case 기준값 = 비교 값
when 비교 값 1 then 참값 1
when 비교 값 2 then 참값 2
when 비교 값3 then 참값3
...
else 기준값
end
case 기준값 = 비교값
when 기준값 = 비교 값 1 then 참값 1
when 기준값 = 비교 값 2 then 참값 2
when 기준값 = 비교 값 3 then 참값 3
...
else 기준값
end
기준값 비교 연산자(=,>,>=, <=,<,!=,^=, in, between and, like) 비교 값
case 기준값 = 비교값
when 기준값 >= 비교 값 1 then 참값 1
when 기준값 <= 비교 값 2 then 참값 2
when 기준값 in(비교 값 3, 비교 값 4) then 참값 3
...
else 기준값
end
● 같은 코드 SELECT employee_id, job_id, case job_id when 'IT_PROG' then salary *1.1 when 'ST_CLERK' then salary * 1.2 when 'SA_REP' then salary * 1.3 else salary end rewised_salary ---별칭 from employees; |
SELECT employee_id, job_id, case when job_id = 'IT_PROG' then salary *1.1 when job_id = 'ST_CLERK' then salary * 1.2 when job_id = 'SA_REP' then salary * 1.3 else salary end rewised_salary from employees; |
[문제29] 사원들의 급여를 기준으로 출력해주세요.
~4999 : low
5000~9999 : medium
10000~19999 : good
20000~ : excellent
SELECT employee_id, salary,
case
when salary between 0 and 4999 then
'low'
when salary >= 5000 and salary < 10000 then
'medium'
when salary >=10000 and salary < 20000 then
'good'
else 'excellent'
end rewised_salary
FROM employees;
'SQL' 카테고리의 다른 글
12.27 오늘의 공부 (0) | 2021.12.27 |
---|---|
12.24 오늘의 공부 (0) | 2021.12.24 |
12.23 오늘의 공부 (0) | 2021.12.23 |
12.22 오늘의 공부 (0) | 2021.12.22 |
12.20 오늘의 공부 (0) | 2021.12.20 |