Database/SQL Server

SQL Server - 달력 만들기 Calendar project

청렴결백한 만능 재주꾼 2021. 1. 19. 23:42
반응형

그냥 숫자만 있는 테이블 Copy_t. 그냥 1부터 999까지 있는 테이블을 사용하여 

'202101' 숫자 여섯개 조건을 넣었을 때에 그 달 달력이 나오게 하는 쿼리를 만들어보려 했다. 

나는 copy_t의 숫자들을 date의 day로 활용하였다. data_type변경 하는 데에 많은 함수가 쓰여졌다. 

 

이전의 달력만들기 포스팅한 것과 차이점이 있는데 이전의 달력만들기에서는 1월달 달력이면 1월달만 표시 되었는데 여기서 만들려고 한 것은 1월달 달력이지만 전년도 12월의 마지막날들이 빈칸에 들어있고 1월 마지막 날 뒤에 다음달 2월의 처음 날짜들이 나오는 것이다.

 

이전의 쿼리문 결과(1월)
이 포스팅의 쿼리문 결과(1월)

CREATE TABLE #CALENDER01 (ID INT IDENTITY(1,1) PRIMARY KEY, YEAR INT, MONTH INT, D_DAY INT , WK INT , DW_NUM INT , DW_NAME NVARCHAR(50))
TRUNCATE TABLE #CALENDER01

DECLARE @INPUT_HERE VARCHAR(6) = '202201'
DECLARE @MONTH INT = 1
WHILE (@MONTH <= 3)
	BEGIN
	DECLARE @INPUT_DATE VARCHAR(6) =  @INPUT_HERE
	DECLARE @CALENDER VARCHAR(8)  = @INPUT_DATE + '01'
	SET @INPUT_DATE = LEFT(CONVERT(VARCHAR(6),DATEADD(M,@MONTH-2,CONVERT(DATETIME,@CALENDER)),112),6)
	SET @CALENDER = @INPUT_DATE + '01'

	INSERT INTO #CALENDER01 (YEAR,MONTH,D_DAY,WK, DW_NUM, DW_NAME)
	SELECT
		DATEPART(YYYY, CONVERT(DATETIME, CASE LEN(CP.NUM) WHEN '1' THEN @INPUT_DATE+'0'+CONVERT(VARCHAR(2), CP.NUM)
		ELSE @INPUT_DATE+CONVERT(VARCHAR(2), CP.NUM)END)) AS [YEAR],
		DATEPART(MM, CONVERT(DATETIME, CASE LEN(CP.NUM) WHEN '1' THEN @INPUT_DATE+'0'+CONVERT(VARCHAR(2), CP.NUM)
		ELSE @INPUT_DATE+CONVERT(VARCHAR(2), CP.NUM)END)),
		CP.NUM D_DAY,
		CASE DATEPART(M,CONVERT(DATETIME,@INPUT_HERE+'01'))
		WHEN 1
		THEN CASE DATEPART(WK,CONVERT(DATETIME, CASE LEN(CP.NUM) WHEN '1' THEN @INPUT_DATE+'0'+CONVERT(VARCHAR(2), CP.NUM)ELSE @INPUT_DATE+CONVERT(VARCHAR(2), CP.NUM)END))-1 WHEN '52' THEN '0' ELSE DATEPART(WK,CONVERT(DATETIME, CASE LEN(CP.NUM) WHEN '1' THEN @INPUT_DATE+'0'+CONVERT(VARCHAR(2), CP.NUM)ELSE @INPUT_DATE+CONVERT(VARCHAR(2), CP.NUM)END))-1 END
		ELSE CASE DATEPART(WK,CONVERT(DATETIME, CASE LEN(CP.NUM) WHEN '1' THEN @INPUT_DATE+'0'+CONVERT(VARCHAR(2), CP.NUM)ELSE @INPUT_DATE+CONVERT(VARCHAR(2), CP.NUM)END))-1 WHEN '0' THEN '52' ELSE DATEPART(WK,CONVERT(DATETIME, CASE LEN(CP.NUM) WHEN '1' THEN @INPUT_DATE+'0'+CONVERT(VARCHAR(2), CP.NUM)ELSE @INPUT_DATE+CONVERT(VARCHAR(2), CP.NUM)END))-1 END
		END AS WK,
		DATEPART(DW,
		CONVERT(DATETIME, CASE LEN(CP.NUM) WHEN '1' THEN @INPUT_DATE+'0'+CONVERT(VARCHAR(2), CP.NUM)
		ELSE @INPUT_DATE+CONVERT(VARCHAR(2), CP.NUM)END)) AS DW_NUM,
		DATENAME(DW,
		CONVERT(DATETIME, CASE LEN(CP.NUM) WHEN '1' THEN @INPUT_DATE+'0'+CONVERT(VARCHAR(2), CP.NUM)
		ELSE @INPUT_DATE+CONVERT(VARCHAR(2), CP.NUM)END)) AS DW_NAME
  	FROM COPY_T CP
 	WHERE CP.NUM BETWEEN 1 AND DATEDIFF(D,CONVERT(DATETIME, @CALENDER),DATEADD(M,1,CONVERT(DATETIME, @CALENDER)))

	SET @MONTH = @MONTH + 1

END

SELECT
	max(CASE DW_NUM WHEN '1' THEN CONVERT(VARCHAR(2), D_DAY) ELSE '' END) AS Su,
	max(CASE DW_NUM WHEN '2' THEN CONVERT(VARCHAR(2), D_DAY) ELSE '' END) AS Mo,
	max(CASE DW_NUM WHEN '3' THEN CONVERT(VARCHAR(2), D_DAY) ELSE '' END) AS Tu,
	max(CASE DW_NUM WHEN '4' THEN CONVERT(VARCHAR(2), D_DAY) ELSE '' END) AS We,
	max(CASE DW_NUM WHEN '5' THEN CONVERT(VARCHAR(2), D_DAY) ELSE '' END) AS Tr,
	max(CASE DW_NUM WHEN '6' THEN CONVERT(VARCHAR(2), D_DAY) ELSE '' END) AS Fr,
	max(CASE DW_NUM WHEN '7' THEN CONVERT(VARCHAR(2), D_DAY) ELSE '' END) AS Sa
  FROM #CALENDER01 C
 WHERE ID BETWEEN DATEPART(D,DATEADD(D,-1,DATEADD(M,-1,@CALENDER)))-DATEPART(DW,DATEADD(M,-1,@CALENDER))+2 AND DATEPART(D,DATEADD(D,-1,DATEADD(M,-1,@CALENDER)))+DATEPART(D,DATEADD(D,-1,@CALENDER))+(7-DATEPART(DW,DATEADD(D,-1,@CALENDER)))
GROUP BY WK

나는 3번 쿼리문을 돌려 입력한 날의 앞뒤전의 달까지 합쳐서 임시 테이블에 넣은 다음 중간을 뽑은 것이다. 하지만 여기서 힘들었던 것은 전달이 전년도인 경우를 어떻게 처리하는 가 였다. 그냥 임시테이블의 id로 처리를 하였다.  

 

만약 1월 달력이 필요하다면 12,1,2월 달력을 뽑은 임시테이블의 딱 중간을 id로 가져오는 걸로 하였다. 중간을 가져오는 것은 where절 참고.

 

 

 


 

 

모범답안, 실무에 쓰인 쿼리문이다. 여기서는 copy_t의 숫자가 주(Week)로 활용이 되었고, 그로인해 쿼리문이 매우 짧아졌다. 그런 비주얼적인 갈무리가 덜 되었지만 기능 구현은 확실히 되었다.

select dateadd(dd, (-1) * (datepart(WEEKDAY, convert(date, '202101' + '01', 112)) - 1) + (cp.num - 1) * 7 + 0, convert(date, '202101' + '01', 112)),
       dateadd(dd, (-1) * (datepart(WEEKDAY, convert(date, '202101' + '01', 112)) - 1) + (cp.num - 1) * 7 + 1, convert(date, '202101' + '01', 112)),
       dateadd(dd, (-1) * (datepart(WEEKDAY, convert(date, '202101' + '01', 112)) - 1) + (cp.num - 1) * 7 + 2, convert(date, '202101' + '01', 112)),
       dateadd(dd, (-1) * (datepart(WEEKDAY, convert(date, '202101' + '01', 112)) - 1) + (cp.num - 1) * 7 + 3, convert(date, '202101' + '01', 112)),
       dateadd(dd, (-1) * (datepart(WEEKDAY, convert(date, '202101' + '01', 112)) - 1) + (cp.num - 1) * 7 + 4, convert(date, '202101' + '01', 112)),
       dateadd(dd, (-1) * (datepart(WEEKDAY, convert(date, '202101' + '01', 112)) - 1) + (cp.num - 1) * 7 + 5, convert(date, '202101' + '01', 112)),
       dateadd(dd, (-1) * (datepart(WEEKDAY, convert(date, '202101' + '01', 112)) - 1) + (cp.num - 1) * 7 + 6, convert(date, '202101' + '01', 112))
  from copy_t cp
where cp.num <= datepart(week, dateadd(dd, -1, dateadd(month, 1, convert(date, '202101' + '01', 112)))) - datepart(week, convert(date, '202101' + '01', 112)) + 1
반응형