오늘도 새로운 쿼리 문에 대해서 배운 것이 있다면 기록을 해보도록 하겠습니다.
시작과 동시에 새로운 명령문을 알게 되었다는 것이 기쁘면서도 점점 어려워진다는 것이 느껴진다.
재귀 쿼리
말로만 들어서는 조금 생소한 표현이지만 쉽게 표현을 하자면
한번 사용한 테이블 내용을 다시 가져와서 한번더 계산을 할 수 있기에 반복적으로 늘어나는 값이나
0~23시까지 하나하나 나누어주어야 하는 일이 필요할 때 유용하게 사용이 될 수 있다.
WITH RECURSIVE Numbers AS (
-- 1. 초기 쿼리: 1부터 시작
SELECT 1 AS NUM
UNION ALL
-- 2. 재귀 쿼리: 이전 숫자에 1을 더함
SELECT NUM + 1
FROM Numbers
-- 3. 종료 조건: 10보다 작을 때만 재귀를 계속함
WHERE NUM < 10
)
-- 생성된 숫자 출력
SELECT * FROM Numbers;
나는 이방법을 이용해서 데이터상에는 나와있지 않은 값을 0으로 표현을 해야 했는데 공간이 있는 자리에 NULL로 표현이 되어 있다면 IF문이나 CASE문을 사용하여 조건식 변경을 해주면 가능하지만
지금 같은 경우에는 아예 쿼리 자체가 존재하지 않는 상황이기에 쿼리를 생성하여주어야 하는 상황이었다.
-- 코드를 입력하세요
WITH RECURSIVE CTE AS(
SELECT 0 AS NUM
UNION ALL
SELECT NUM+1 FROM CTE
WHERE NUM < 23
)
SELECT C.NUM HOUR, IFNULL(COUNT,0) COUNT
FROM CTE C LEFT JOIN (
SELECT HOUR(DATETIME) HOUR, COUNT(1) COUNT
FROM ANIMAL_OUTS
GROUP BY 1
) H ON C.NUM = H.HOUR
위에서 보다시피 재귀쿼리를 사용하기 위해서는 WITH문과 RECURSIVE를 사용하여 반복이 가능하도록 만들어주고
안쪽에서는 UNION문을 이용 하나하나 NUM을 추가하여 칼럼을 만들어주는 방식을 이용하였습니다.
또한 추가적인 방법으로 IF문에서 NULL을 바로 변경하는 명령문으로 IFNULL을 사용하면 된다는 것을 알았습니다.
다중 조건의 해결
이번 문제를 해결하기 위해서 정말 머리를 많이 썼었는데
수만을 오류와 문제로 골머리를 가졌다.
문제의 조건을 찾아보자면
1. 자동차들 중에서 세단과 SUV인 것들이어야 한다.
2. 기간들 중에 2022-11-1일부터 2022-11-30일까지 대여가 가능한 차종이어야 하며
3. 30일을 빌릴 예정에 그 총금액이 50만 원에서 200만 원 사이인 값을 원한다고 합니다.
이를 위해 WITH문을 사용하여 작성을 하였습니다.
-- 코드를 입력하세요
WITH TEMP1 AS(
SELECT CAR_ID, MAX(END_DATE)
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
GROUP BY 1
HAVING YEAR(MAX(END_DATE)) <2023 AND MONTH(MAX(END_DATE)) < 11
),
TEMP2 AS(
SELECT T1.CAR_ID, B.CAR_TYPE, B.DAILY_FEE
FROM TEMP1 T1 INNER JOIN CAR_RENTAL_COMPANY_CAR B ON T1.CAR_ID = B.CAR_ID
WHERE B.CAR_TYPE IN ('SUV', '세단')
),
TEMP3 AS(
SELECT T2.CAR_ID, T2.CAR_TYPE,
ROUND(T2.DAILY_FEE * 30 * (100 - C.DISCOUNT_RATE) / 100, 0) as FEE
FROM TEMP2 T2 INNER JOIN CAR_RENTAL_COMPANY_DISCOUNT_PLAN C ON T2.CAR_TYPE = C.CAR_TYPE
WHERE C.DURATION_TYPE = '30일 이상'
)
SELECT *
FROM TEMP3
WHERE FEE BETWEEN 500000 AND 1990000
ORDER BY FEE DESC, CAR_TYPE, CAR_ID DESC
여기서 처음부터 고난이었던 점은 2022년 11월 동안 대여가 가능한 차량을 검색을 위해 어떻게 조건을 걸어줘야
하는지 큰 고난이 찾아왔습니다.
알고리즘을 짜보면 일단 11월 1일에 이미 대여가 되어 있는 차량이 되어서는 안 되고
11월 30까지 대여가 예약이 되어있으면 안 되는 차량을 찾아야 하는 것인데
이것을 조건문으로 표현을 한다는 것이 문제였습니다.
2011-11-01~2011-11-30이라는 기간에 시작일과 반납일이 안 들어 있는 차량을 찾아내는 것이 어려웠다.
처음 문제를 끝내자 말자 다음문제는 바로 고난이 시작되었는데.
1번과 2번 테이블의 조합으로 대여일을 찾아야 하고 1번과 3번으로 빌린 트럭의 대여일에 맞추어서 할인율을 찾아내야
하는 것이었는데 문제가 되는 점이 3번 테이블을 보면 차종과 날짜에 맞추어 할인율이 달라지는데
다른 테이블과 엮기 위에서 엮는 방법이 CAR_TYPE을 이용해서 붙이는 방법 밖에 없었다.
그래서 JOIN을 이용하여 붙여보았을 때 문제가 되는 점이 트럭에 관한 조건으로
7,30,90일이 각각 하나씩 만들어지는 것이 문제가 되었다.
WITH DATE AS (
SELECT *,
DATEDIFF(END_DATE, START_DATE) + 1 AS DAYS,
CASE
WHEN DATEDIFF(END_DATE, START_DATE) + 1 < 7 THEN NULL
WHEN DATEDIFF(END_DATE, START_DATE) + 1 < 30 THEN '7일 이상'
WHEN DATEDIFF(END_DATE, START_DATE) + 1 < 90 THEN '30일 이상'
ELSE '90일 이상'
END AS D_DAY
FROM CAR_RENTAL_COMPANY_CAR A
JOIN CAR_RENTAL_COMPANY_RENTAL_HISTORY B USING(CAR_ID)
)
SELECT HISTORY_ID,
ROUND(DAILY_FEE * DAYS * ((100 - COALESCE(DISCOUNT_RATE, 0)) / 100), 0) AS FEE
FROM DATE A
LEFT JOIN CAR_RENTAL_COMPANY_DISCOUNT_PLAN B
ON A.CAR_TYPE = B.CAR_TYPE AND A.D_DAY = B.DURATION_TYPE
WHERE A.CAR_TYPE = '트럭'
ORDER BY FEE DESC, HISTORY_ID DESC;
그것 때문에 이 방법을 해결하기 위해 엄청난 머리를 싸매었지만 인터넷을 검색하여 찾아본 결과
JOIN을 할 때 AND을 사용하여 1차을 이어 2차적으로 동일한 값에만 JOIN을 달아줄 수 있다는 것을 알게 되었습니다.
그렇게 되면 1번과 2번 테이블의 합으로 날짜를 계산하여서 해당하는 날짜에만 값을 넣어주는 칼럼을 생성해 주고
JOIN을 2차로 걸쳐 넣어주면 해당하지 않는 값들은 전부 NULL로 들어가기에 필터링을 해주면 되는 것입니다.
그리고 할인율에 맞추어 값을 넣어주기 위해 COALESCE(DISCOUNT_RATE, 0)를 넣어 줘야 하는데
JOIN으로 인하여 생겨버린 NULL 때문에 필요하지 않은 값은 뛰어넘고 계산을 할 수 있도록 하여 식을 완성해 주면 된다.
서브쿼리의 이용
-- 코드를 입력하세요
SELECT YEAR(SALES_DATE) YEAR, MONTH(SALES_DATE) MONTH,
COUNT(DISTINCT USER_ID) PUCHASED_USERS,
ROUND(COUNT(DISTINCT USER_ID)/(SELECT COUNT(DISTINCT USER_ID)
FROM USER_INFO
WHERE YEAR(JOINED) = 2021 ), 1) PUCHASED_RATIO
FROM USER_INFO A JOIN ONLINE_SALE B USING(USER_ID)
WHERE YEAR(JOINED) = 2021
GROUP BY 1, 2
ORDER BY 1, 2
이 문제를 해결하기 위해서는 서브 쿼리문은 적극적으로 이용을 하여서 코딩을 단순하게 만들어 주는 것이 필요하다.
GIT에 대하여 알아보자
Git 커밋
COMMIT : 아랫 단계를 만들어 주는 것???
기존에 있는 것에 자식을 만들어 주는 것이며 c2의 부모가 c1이 된다.
Git 브랜치
branch : 브랜치는 특정 커밋에 대한 참조(reference)에 지나지 않습니다
같은 c1안에 새로운 newImage를 넣어주는 것이 branch이다.
이 상태에서 commit을 하게 된다면 현재 선택이 되어있는 main이 내려가며 newimage는 c1에 남아있게 된다.
새로운 명령어 checkout을 통하여 브랜치명을 선택하여 줄 수 있다.
그다음에 commit을 하여 newimage를 c2로 보내줄 수 있다.
브랜치와 합치기(Merge)
merge : 두 개의 브랜치를 합치는
git에서 서로 다른 작업을 했던 것들을 다시 붙이는 방법으로 MERGE가 있다.
붙이는 방법으로 MAIN을 CHECKOUT 하고 MERGE '브리지'를 한 다음에 대상을 브리지로 옮기고 다시 MERGE MAIN을 하면 서로 같은 위치에 커밋으로 이동할 수 있다.
Git 리베이스(Rebase)
MERGE와 같은 기능으로 브랜치 끼리 서로 작업을 접목하는 기능을 하는 REBASE다.
Git에서 여기저기로 옮겨 다니기
git에서 이동할 수 있는 방법
HEAD
HEAD는 현재 체크아웃된 커밋을 가리킵니다
HEAD는 항상 작업트리의 가장 최근 커밋을 가리킵니다.
상대 참조
매번 해시를 확인하려고 git log 명령어를 치고 있을 겁니다
Git의 상대 참조(Relative Ref)가 여기서 등장합니다
- 한 번에 한 커밋 위로 움직이는 ^
- 한번에 여러 커밋 위로 올라가는 ~<num>
커밋트리에서 위로 여러 단계를 올라가고 싶을 수 있습니다.
^를 계속 입력해서 올라가는 것 말고 좋은 방법이 있습니다.
Git 에는 틸드 (~) 연산자가 있습니다.
(~) 틸드 연산자는 (선택적) 올라가고 싶은 부모의 개수가 뒤에 숫자가 옵니다
브랜치 강제로 옮기기
-f 옵션을 이용해서 브랜치를 특정 커밋에 직접적으로 재지정할 수 있습니다
git branch -f main HEAD~3
(강제로) main 브랜치를 HEAD에서 세 번 뒤로 옮겼습니다. (three parents behind HEAD)
Git에서 작업 되돌리기
Git에서 변경한 내용을 되돌리는 방법은 크게 두 가지가 있습니다 --
하나는 git reset을 쓰는 거고,
다른 하나는 git revert를 사용하는 것입니다.
Git 리셋(reset)
각자의 컴퓨터에서 작업을 하는 상황에 사용을 하기 좋다.
Git 리버트(revert)
로컬로 작업을 하여 수시로 정보를 공유받아야 하는 경우에 사용하기 좋
뒤로 가기 : undo, 초기화 : reset 도 있다.
작업을 여기저기로 옮기기
Git 체리-픽 (Cherry-pick)
첫 명령어는 git cherry-pick입니다. 다음과 같은 형태로 사용합니다:
git cherry-pick <Commit1> <Commit2> <...>
현재 위치(HEAD) 아래에 있는 일련의 커밋들에 대한 복사본을 만들겠다는 것을 간단히 줄인 말입니다
Git 인터렉티브 리베이스(Interactive Rebase)
인터렉티브 리베이스가 의미하는 뜻은 rebase 명령어를 사용할 때 -i 옵션을 같이 사용한다는 것입니다
실제" git에서는 UI창을 띄우는 것 대신에 vim과 같은 텍스트 편집기에서 파일을 엽니다
'코딩 교육 TIL' 카테고리의 다른 글
2024-01-23 AI 코딩 TIL (0) | 2024.02.16 |
---|---|
2024-01-22 AI 코딩 TIL (0) | 2024.02.16 |
2024-02-16 AI 코딩 TIL (1) | 2024.02.16 |
2024-02-14 AI 코딩 TIL (1) | 2024.02.14 |
2024-02-13 AI 코딩 TIL (1) | 2024.02.13 |