일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- mysql
- react
- 도메인 주도 개발 시작하기
- AWS RDS
- 기술면접
- CleanCode
- 알고리즘
- 클린코드
- aop
- 자바예외
- SQL쿡북
- DDD
- 인프런백기선
- jpa
- java
- AWS
- 네트워크
- 이펙티브 자바
- 자바스터디
- vue.js
- 이팩티브 자바
- 인프런김영한
- 자료구조
- 이펙티브자바
- MariaDB
- 인덱스
- 알고리즘분석
- 혼공SQL
- 스프링부트와AWS로혼자구현하는웹서비스
- 자바
- Today
- Total
기록이 힘이다.
[SQL 쿡북] 8. 날짜 산술 본문
기본적인 날짜 산술에 중점을 두고 설명합니다. 다음 장에서는 더 많은 고급 날짜 레시피를 찾아볼 수 있습니다.
8.1 일, 월, 연도 가감하기
8.2 두 날짜 사이의 일수 알아내기
MySQL의 DATEDIFF에는 두 개의 매개변수(차이를 찾을 두 날짜)만 필요하며, 음숫값을 피하고자 두 날짜 중 더 작은 날짜를 먼저 전달해야 합니다.(SQL Server와 반대).
8.3 두 날짜 사이의 영업일수 알아내기
휴일도 제외하려면 HOLIDAYS 테이블을 만들어서 처리합니다. 해법에서 간단한 NOT IN 술어를 추가하여 HOLIDAYS에 나열된 날짜를 제외합니다.
select max(case when ename = 'BLAKE'
then hiredate
end) as blake_hd,
max(case when ename = 'JONES'
then hiredate
end) as jones_hd
from emp
where ename in ( 'BLAKE','JONES' )
select sum(case when date_format(
date_add(jones_hd,
interval t500.id-1 DAY),'%a')
in ( 'Sat','Sun' )
then 0 else 1
end) as days
from (
select max(case when ename = 'BLAKE'
then hiredate
end) as blake_hd,
max(case when ename = 'JONES'
then hiredate
end) as jones_hd
from emp
where ename in ( 'BLAKE','JONES' )
) x,
t500
where t500.id <= datediff(blake_hd,jones_hd)+1
1. 시작 날짜와 종료 날짜 사이의 날짜(포함)을 반환합니다.
2. 주말을 제외하고 며칠(행)이 있는지 계산합니다.
WHERE 절을 살펴보면 BLAKE_HD와 JONES_HD의 차이에 1을 더하여 필요한 30개 행을 생성함을 알 수 있습니다.(그렇지 않으면 29개 행이 생성됩니다.) 또한 ID 값이 1에서 시작하고 JONES_HD에 1을 더하면 JONES_HD가 최종 개수에서 제외될 수 있으므로, 외부 쿼리의 SELECT 목록에 있는 T500.ID에서 1을 빼는 것을 확인 할 수 있습니다.
결과셋에 필요한 행 수를 생성한 후에는 CASE 표현식을 사용하여 반환된 각 요일이 평일인지 주말인지 여부를 표시(평일에는 1을, 주말에는 0을 반환) 마지막 단계는 집계함수 SUM을 사용하여 1인 수를 집계하여 최종 답을 도출합니다.
8.4 두 날짜 사이의 월 또는 년 수 알아내기
1년은 항상 12개월이므로 두 날자 사이의 개월 수를 찾은 다음 12로 나누어 연도를 구할 수 있습니다. 해법에 익숙해지면 원하는 연도에 따라 결과를 반올림합니다. 예를 들어 EMP테이블의 첫 번째 HIREDATE는 12-DEC-1980이고 마지막은 12-JAN-1983입니다. 연도(1983-1908)에 대해 계산하면 3년이 되지만, 개월 차이는 (2년이 조금 넘는) 약 25개월입니다. 적합하다고 판단되는 쪽으로 조정해야 합니다. 다음 해법에서는 25개월 및 약 2년을 반환합니다.
YEAR 및 MONTH 함수를 사용하여 제공된 날짜에 대해 4자리 연도와 2자리 월을 반환합니다.
<DB2와 MySQL>
select mnth, mnth/12
from (
select (year(max_hd) - year(min_hd))*12 +
(month(max_hd) - month(min_hd)) as mnth
from (
select min(hiredate) as min_hd, max(hiredate) as max_hd
from emp
) x
) y
8.5 두 날짜 사이의 시,분,초 알아내기
select datediff(allen_hd,ward_hd)*24 hr,
datediff(allen_hd,ward_hd)*24*60 min,
datediff(allen_hd,ward_hd)*24*60*60 sec
from (
select max(case when ename = 'WARD'
then hiredate
end) as ward_hd,
max(case when ename = 'ALLEN'
then hiredate
end) as allen_hd
from emp
) x
8.6 1년 중 평일 발생 횟수 계산하기
1. 연도에 가능한 모든 날짜를 생성합니다.
2. 해당 요일의 이름이 나오도록 날짜 형식을 지정합니다.
3. 각 요일의 발생 횟수를 셉니다.
<MySQL>
select date_format(
date_add(
cast(
concat(year(current_date),'-01-01')
as date),
interval t500.id-1 day),
'%W') day,
count(*)
from t500
where t500.id <= datediff(
cast(
concat(year(current_date)+1,'-01-01')
as date),
cast(
concat(year(current_date),'-01-01')
as date))
group by date_format(
date_add(
cast(
concat(year(current_date),'-01-01')
as date),
interval t500.id-1 day),
'%W')
테이블 T500에 대해 선택하여 해당 연도의 모든 일을 반환하기에 충분한 행을 생성합니다. DATE_FORMAT 함수를 사용하여 각 날짜의 요일명을 얻은 다음 요일별 발생 횟수를 계산합니다.
8.7 현재 레코드와 다음 레코드 간의 날짜 차이 알아내기
select x.ename, x.hiredate, x.next_hd,
datediff(x.next_hd, x.hiredate) as diff
from (
select deptno, ename, hiredate,
lead(hiredate)over(order by hiredate) as next_hd
from emp e
) x
where e.deptno=10
윈도우 함수 LEAD를 사용한 다음, 8.2절에서 설명한 기술을 사용하여 두 날짜 간의 차이를 찾습니다.
추가적인 조인 없이 현재 행 주변의 행에 액세스하여 더 읽기 쉽고 효율적인 코드를 제공합니다.
8.8 마치며
날짜는 일반적인 데이터 유형이지만, 단순한 숫자 데이터 유형보다 구조가 더 복잡한 만큼 독특합니다. 핵심 함수들을 마스터하면 날짜를 쉽게 처리할 수 있습니다.
'SQL' 카테고리의 다른 글
[SQL 쿡북] 10. 범위 관련 작업하기 (0) | 2023.04.08 |
---|---|
[SQL 쿡북] 9.날짜 조작 기법 (0) | 2023.04.04 |
[SQL 쿡북] 7. 숫자작업(18) (0) | 2023.03.18 |
[SQL 쿡북] 6. 문자열 작업(18) p150 (1) | 2023.03.12 |
[SQL 쿡북] 5. 메타 데이터 쿼리(8) p133 (0) | 2023.03.07 |