HackerRank: SQL 풀이(31~40)

SeongGyun Hong·2024년 12월 12일

SQL

목록 보기
16/51

31. Weather Observation Station 2

MS SQL Server에서 ROUND 함수는 기본적으로 숫자를 지정된 소수 자릿수로 반올림만틈만 하고, 그 뒤의 자릿수를 제거하지 않는 경우가 있다.
이 문제를 해결하려면 출력 형식을 명확히 제어해야 한다.
그니까 간단히 말하자면

  • ROUND(~, 2) 이런식으로 하면
    42850.0400000000 47381.4800000000
    이렇게 밖에 안 나옴 깔끔하게 두번째 자리까지 나오는게 아님.
    두번째 자리까지 나오게 하려면
    CAST 를 활용하든지, Format을 활용하든지 해야함.
    그중 Format이 길지 않고 간결하므로 이하에서는 FORMAT을 사용... 하고자 하였으나
    FORMAT 함수의 경우 문자열을 뱉어냄... 그래서그냥 CAST 쓰기로 함...
  • 요약하자면 아래 두 쿼리가 다른 거임! 하나는 문자열 하나는 숫자!
SELECT FORMAT(ROUND((SUM(LAT_N)), 2), 'N2'), FORMAT(ROUND((SUM(LONG_W)), 2), 'N2')
FROM STATION;

# 42,850.04 47,381.48 >> 문자열

SELECT 
    CAST(ROUND(SUM(LAT_N), 2) AS NUMERIC(10, 2)) AS Sum_Latitude,
    CAST(ROUND(SUM(LONG_W), 2) AS NUMERIC(10, 2)) AS Sum_Longitude
FROM STATION;
# 42850.04 47381.48 >> 숫자

CAST 기본 문법

CAST(expression AS data_type)

매개변수:

  1. expression: 변환하려는 값(숫자, 문자열, 날짜 등).
  2. data_type: 변환하려는 대상 데이터 타입(예: INT, DECIMAL, VARCHAR, DATETIME 등).

주요 특징:

  1. 데이터 타입 간 변환:
    • 숫자를 문자로, 문자를 숫자로, 날짜를 문자로 변환 가능.
  2. 정밀한 데이터 제어:
    • 소수점 자리, 문자열 길이 등 세부 설정 가능.
  3. SQL 표준 준수:
    • CAST는 모든 SQL 표준을 지원하는 DBMS에서 사용 가능.

예제별 사용법

1. 숫자를 고정 소수점 형식으로 변환

소수점 이하 2자리까지만 표시:

SELECT CAST(123.4567 AS DECIMAL(10, 2)) AS RoundedValue;

결과:

RoundedValue
123.46

2. 문자열을 숫자로 변환

숫자로 변환 가능한 문자열을 숫자로 변환:

SELECT CAST('12345' AS INT) AS NumericValue;

결과:

NumericValue
12345

3. 숫자를 문자열로 변환

숫자를 문자열로 변환하여 특정 형식 출력:

SELECT CAST(12345 AS VARCHAR(10)) AS StringValue;

결과:

StringValue
12345

4. 날짜를 문자열로 변환

날짜 데이터를 문자열로 변환:

SELECT CAST(GETDATE() AS VARCHAR(20)) AS DateAsString;

결과:

DateAsString
2024-12-12 13:45:00

5. 문자열을 날짜로 변환

날짜 형식의 문자열을 실제 날짜 데이터로 변환:

SELECT CAST('2024-12-12' AS DATE) AS DateValue;

결과:

DateValue
2024-12-12

6. 소수점 이하 자릿수 제한

소수점을 특정 자리까지 제한(숫자 데이터 유지):

SELECT CAST(ROUND(123.456789, 2) AS DECIMAL(10, 2)) AS RoundedValue;

결과:

RoundedValue
123.46

CAST와 관련된 데이터 타입

  1. 숫자형: INT, FLOAT, DECIMAL(precision, scale)

    • DECIMAL(precision, scale):
      • precision: 전체 자리 수.
      • scale: 소수점 아래 자리 수.
    • 예: DECIMAL(10, 2) → 최대 10자리, 소수점 이하 2자리.
  2. 문자형: CHAR(n), VARCHAR(n)

    • n은 최대 문자 길이.
  3. 날짜/시간형: DATE, DATETIME, TIME

  4. 이진형: BINARY, VARBINARY


CASTCONVERT의 차이

  • CAST:
    • SQL 표준 준수.
    • 이식성이 높음.
    • 간단한 데이터 타입 변환에 적합.
  • CONVERT:
    • MS SQL Server 전용 함수.
    • 형식 스타일(날짜, 숫자 포맷)을 추가로 지정 가능.
    • 예:
      SELECT CONVERT(VARCHAR, GETDATE(), 103) AS FormattedDate;
      결과: 12/12/2024

  • 정답
SELECT CAST(ROUND(SUM(LAT_N), 2) AS NUMERIC(10,2)), CAST(ROUND(SUM(LONG_W), 2) AS NUMERIC(10,2))
FROM STATION;

32. Weather Observation Station 13

SELECT CAST(SUM(LAT_N) AS NUMERIC(10,4))
FROM STATION
WHERE LAT_N > 38.7880
AND LAT_N < 137.2345;

MS SQL Server에는 TRUNC 같은 함수는 없다. CAST로 대부분 처리하거나 ROUND CEILNG, FLOOR로 처리

33. Weather Observation Station 14

SELECT CAST(MAX(LAT_N) AS NUMERIC(10,4))
FROM STATION
WHERE LAT_N < 137.2345;

34. Weather Observation Station 15

SELECT TOP 1 CAST(ROUND(LONG_W,4) AS NUMERIC(10,4))
FROM STATION
WHERE LAT_N = (SELECT MAX(LAT_N) FROM STATION WHERE LAT_N < 137.2345);

이건 문제가 말이 좀 어려웠다...

35. Weather Observation Station 16

SELECT CAST(ROUND(MIN(LAT_N), 4) AS NUMERIC(10, 4))
FROM STATION
WHERE LAT_N > 38.7780;

36. Weather Observation Station 17

SELECT TOP 1 CAST(ROUND(LONG_W, 4) AS NUMERIC(10,4))
FROM STATION
WHERE LAT_N = (SELECT MIN(LAT_N) FROM STATION WHERE LAT_N > 38.7780);

37. Weather Observation Station 18

SELECT CAST(ROUND((MAX(LAT_N) + MAX(LONG_W) - MIN(LAT_N) - MIN(LONG_W)), 4) AS NUMERIC(10,4))
FROM STATION;

38. Weather Observation Station 19

SELECT CAST(SQRT(POWER(MAX(LAT_N) - MIN(LAT_N), 2) + POWER(MAX(LONG_W) - MIN(LONG_W), 2)) AS NUMERIC(10,4))
FROM STATION;

POWER => 제곱
SQRT => 루트

39. Weather Observation Station 20

  • 집계함수는 아래처럼 WHERE절에 못써요 ~ 서브쿼리로 넣어주세요 ~
WITH NUM_PLUS AS (
    SELECT LAT_N, ROW_NUMBER() OVER (ORDER BY LAT_N) AS RowAsc
    FROM STATION
    )
SELECT CAST(ROUND(LAT_N, 4) AS NUMERIC(10,4))
FROM NUM_PLUS
WHERE RowAsc = CEILING(COUNT(RowAsc)/2);
  • 2.0으로 나누는 거랑 2로 나누는거랑 다릅니다 ~ 정수를 정수로 나누면 정수가 나옵니다~ 그니까 실수로 나눠줘요 홀수로 떨어질때 제대로 중앙값 구할 수 있어요~
WITH NUM_PLUS AS (
    SELECT LAT_N, ROW_NUMBER() OVER (ORDER BY LAT_N) AS RowAsc
    FROM STATION
    )
SELECT CAST(ROUND(LAT_N, 4) AS NUMERIC(10,4))
FROM NUM_PLUS
WHERE RowAsc = (SELECT CEILING(COUNT(*)/2.0) 
                FROM STATION);

그니까 위에가 맞지
아래는 틀렸습니다~

WITH NUM_PLUS AS (
    SELECT LAT_N, ROW_NUMBER() OVER (ORDER BY LAT_N) AS RowAsc
    FROM STATION
    )
SELECT CAST(ROUND(LAT_N, 4) AS NUMERIC(10,4))
FROM NUM_PLUS
WHERE RowAsc = (SELECT CEILING(COUNT(*)/2) 
                FROM STATION);

39. The Report

CASE문에서 DESC, ASC 같은 정렬지시자는 사용 불가하다.
그래서 아래와 같은 query는 안 된다.


SELECT CASE 
        WHEN G.Grade < 8 THEN 'NULL'
        ELSE S.NAME
        END, 
        G.Grade, 
        S.Marks
FROM Students AS S, Grades AS G
WHERE S.MarkS >= G.Min_Mark
AND S.MarkS <= G.Max_Mark
ORDER BY CASE
          WHEN G.Grade >= 8 THEN G.Grade DESC, NAME
          ELSE G.Grade DESC, S.Marks ASC
         END;
         
         
# Msg 156, Level 15, State 1, Server dbrank-tsql, Line 17
# Incorrect syntax near the keyword 'DESC'.

그래서 다음과 같은 식으로 해줘야 한다...?

SELECT CASE 
        WHEN G.Grade < 8 THEN 'NULL'
        ELSE S.NAME
        END, 
        G.Grade, 
        S.Marks
FROM Students AS S, Grades AS G
WHERE S.MarkS >= G.Min_Mark
AND S.MarkS <= G.Max_Mark
ORDER BY G.Grade DESC, CASE
                        WHEN G.Grade >=8 THEN S.NAME
                        ELSE S.Marks
                       END;

그런데 이렇게 하면 에러난다 ;;;
CASE문의 반환값은 항상 같은 Type을 가져야하기 때문... 헐 ;;

그래서 CASE문을 따로 나눠서 넣어줘야한다...

SELECT CASE 
        WHEN G.Grade < 8 THEN 'NULL'
        ELSE S.NAME
        END, 
        G.Grade, 
        S.Marks
FROM Students AS S, Grades AS G
WHERE S.MarkS >= G.Min_Mark
AND S.MarkS <= G.Max_Mark
ORDER BY G.Grade DESC, CASE
                        WHEN G.Grade >=8 THEN S.NAME
                        ELSE NULL
                       END,
                       CASE
                        WHEN G.Grade < 8 THEN S.Marks
                        ELSE NULL
                       END;
  • 허허 참 신비로운 SQL의 세계..!
    참고로 ELSE NULL은 없어도 암묵적으로 작동하나, 가시성 및 의도를 명확히 반영하기 위해 NULL로 처리해주었다.
profile
헤매는 만큼 자기 땅이다.

0개의 댓글