서론

기존에 있던 프로그램을 유지보수 하던 중 요청이 하나 들어왔다. 요청이 들어온 페이지의 기능은 달력 형식의 페이지가 있고 오늘 이후의 날짜 중에 등록된 데이터가 있는 날짜는 선택할 수 있도록 되어 있는 페이지였다.

예를 들어 오늘 날짜 기준으로(2019년 5월 9일) 페이지를 열면 5월 달력이 뜨며 오늘 기준으로 전 날짜들은 선택을 할 수 없게 뜨고 오늘 이후 날짜 중엔 데이터가 있는 날짜들은 선택 버튼이 뜨게 된다. 아래 스크린샷을 참고하면 될 듯 하다.

대략적인 페이지는 위와 같고 하고자 하는 것은 오늘 날짜,시간 기준으로 18시 이후가 되면 그 다음날 예약가능 버튼은 없어져야 한다.

문제는 현재 저 View 페이지의 달력 JSP 안에서 자바소스와 HTML소스가 짬뽕되어 만들어져 있기 때문에 상당히 복잡한 상태이다. 그래서 애초에 DB에서 조회해온 데이터에 18시 이후가 되면 다음날 데이터를 조회하지 않도록 하는게 나을 것 같았다.

본론

SELECT DAYS
FROM
    (
      SELECT TO_CHAR(BASE_MON+LEVEL-1,'YYYYMMDD') AS DAYS
      FROM 
          ( 
            SELECT TRUNC(SYSDATE,'MM') AS BASE_MON
            FROM DUAL 
          ) T 
      WHERE 1=1 
      CONNECT BY BASE_MON+LEVEL-1 <= LAST_DAY(BASE_MON)
    )
WHERE DAYS >= TO_CHAR(SYSDATE, 'YYYYMMDD')

실제 쿼리는 위 쿼리보다 복잡하지만 간소화하여 만들어보았다. 보면 알겠지만 먼저 지금 SYSDATE 기준으로 첫 1일의 년월일 값을 구하여 그것을 바탕으로 CONNECT BY를 이용하여 그 달의 1일부터 마지막 일까지 데이터들을 생성해준다. 위 쿼리를 실행하면 아래와 같이 나온다.

참고로 WHERE절의 조건 때문에 오늘 이전의 날들은 나오지 않게 된다. 위 쿼리를 바탕으로 이것저것 쿼리가 더 추가되어 그 날에 데이터가 있는지 없는지 분간할 수 있게 되는데 지금은 별로 관계없는 부분이기도 하고 실제 운영 중인 서비스에 쓰이는 쿼리라 따로 설명하진 않겠다.

아무튼 오늘 날짜 ~ 이번 달의 마지막 날짜까지 쿼리로 구하였다. 여기서 이제 현재 시간이 18시 이후라면 내일 날짜를 없애버리는 것이 오늘의 목표이다.

SELECT DAYS
FROM
    (
      SELECT TO_CHAR(BASE_MON+LEVEL-1,'YYYYMMDD') AS DAYS
      FROM 
          ( 
            SELECT TRUNC(SYSDATE,'MM') AS BASE_MON
            FROM DUAL 
          ) T 
      WHERE 1=1 
      CONNECT BY BASE_MON+LEVEL-1 <= LAST_DAY(BASE_MON)
    )
WHERE DAYS >= TO_CHAR(SYSDATE, 'YYYYMMDD');
    AND DAYS NOT LIKE 
       CASE 
              WHEN TO_DATE(TO_CHAR(SYSDATE, 'YYYYMMDDHH24MI'),'YYYYMMDDHH24MI')-TO_DATE(TO_CHAR(SYSDATE, 'YYYYMMDD')||'1800', 'YYYYMMDDHH24MI') > 0 THEN TO_CHAR(SYSDATE+1, 'YYYYMMDD') 
                   ELSE ' ' 
                   END

위와 같이 조건건을 하나 추가해주었다. 한줄한줄 살펴보자면,

AND DAYS NOT LIKE : DAYS가 오른쪽의 값과 같지 않은 것만 보여줄 것인데,

CASE WHEN TO_DATE(TO_CHAR(SYSDATE, 'YYYYMMDDHH24MI'),'YYYYMMDDHH24MI')-TO_DATE(TO_CHAR(SYSDATE, 'YYYYMMDD') ||'1800', 'YYYYMMDDHH24MI') > 0 THEN : CASE문을 통해 조건을 걸어준다. 현재 시간을 201905091800 식으로 변환한 뒤, 역시나 오늘 날짜+’1800’을 변환하여 서로 빼준다. 현재 시간에서 오늘 날짜의 18시를 빼주었을 때, 만약 현재 시간이 18시 이전이면 음수, 18시 이후면 양수가 나오게 된다. 그래서 뒤에 조건에 >0을 써주었다. 한줄로 해석하자면 현재 시간이 18시 이후일 때이다.

TO_CHAR(SYSDATE+1, 'YYYYMMDD') 만약 18시 이후라면 DAYS와 비교해줄 값을 오늘 날짜+1일을 하여 20190510 식으로 리턴해준다.

ELSE ' ' END 다른 경우들은 모두 공백값을 리턴해준다. 그래야 NOT LIKE에 필터링 되지 않고 정상적으로 나오기 때문이다.

결과적으로 만약 18시 이전이라면 AND DAYS NOT LIKE ' ' 이렇게 나올 것이고, 18시 이후라면 AND DAYS NOT LIKE '20190510' 이렇게 나오게 된다.

아래 스크린샷이 특정 시간이 지났을 경우 나오는 값들이다. 보시다시피 20190510이 빠지게 되었다.

괜히 JSP에서 Calendar나 SimpleDateFormat을 생성하여 복잡하게 날짜 비교를 하지 않고 간단하게 쿼리를 통해 해결할 수 있었다.