Algorithm/Programmers SQL

[MySQL] 프로그래머스 조건에 맞는 사용자 정보 조회하기

제우제우 2024. 9. 15. 23:02

https://school.programmers.co.kr/learn/courses/30/lessons/164670

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

코딩테스트 연습 > String, Date > 조건에 맞는 사용자 정보 조회하기

 

문제 분석

난이도: LEVEL3

 

문제 요구사항

USED_GOODS_BOARD와 USED_GOODS_USER 테이블에서 중고 거래 게시물을 3건 이상 등록한 사용자의 사용자 ID, 닉네임, 전체 주소, 전화번호를 조회하는 SQL 문을 작성해 주세요. 

이때, 전체 주소는 시, 도로명 주소, 상세 주소가 함께 출력되도록 해주시고, 전화번호의 경우 xxx-xxxx-xxxx 같은 형태로 하이픈 문자열(-)을 삽입하여 출력해 주세요. 

결과는 회원 ID를 기준으로 내림차순 정렬해 주세요.

 

사용한 함수 설명

CONCAT_WS() 함수

여러 개의 문자열을 결합할 때 구분자(Separator)를 자동으로 삽입하여 연결해주는 함수.

WS는 "With Separator"의 약자이다. 즉, 문자열을 결합할 때마다 지정된 구분자를 사이에 넣어준다.

구분자를 제공하지 않으면 자동으로 구분자가 없는 CONCAT()와 동일하게 작동

결합할 값이 NULL이면 해당 값은 무시

 

구문

CONCAT_WS(separator, str1, str2, str3, ...)
  • separator: 문자열 사이에 삽입할 구분자. (, / * - ) 
  • str1, str2, str3, ...: 결합할 문자열들 

예시

SELECT CONCAT_WS('-', '010', '7456', '4564'); -- 010-7456-4564

 

INSERT() 함수

INSERT() 함수는 문자열의 특정 위치에 새로운 문자열을 삽입하는 함수.

기존 문자열의 일부분을 대체하거나, 새로운 문자열을 삽입할 수 있다.

 

구문

INSERT(original_string, position, length, new_string)
  • original_string: 수정할 원본 문자열
  • position: 새로운 문자열을 삽입할 위치 (1부터 시작)
  • length: 대체할 기존 문자열의 길이. 0으로 설정하면 기존 문자열을 대체하지 않고 삽입만 한다. 
  • new_string: 삽입할 새로운 문자열

특징

  • position에 지정된 위치에서부터 시작해, length만큼의 기존 문자를 대체
  • length를 0으로 설정하면 기존 문자열을 대체하지 않고 새로운 문자열을 그 위치에 삽입

예시

SELECT INSERT('01074564564', 4, 0, '-'); -- 010-74564564

 

정답 코드1

SELECT
USER_ID,
NICKNAME,
CONCAT_WS(' ', CITY, STREET_ADDRESS1, STREET_ADDRESS2) 전체주소, 
CONCAT_WS('-', SUBSTRING(TLNO, 1, 3), SUBSTRING(TLNO, 4, 4), SUBSTRING(TLNO, 8, 4)) 전화번호 
FROM USED_GOODS_USER
WHERE USER_ID IN (SELECT WRITER_ID 
                  FROM USED_GOODS_BOARD
                  GROUP BY WRITER_ID 
                  HAVING COUNT(*) >= 3)
ORDER BY 1 DESC

 

지금 WHERE 보면 각 ROW 마다 매번 서브 쿼리가 실행된다. (성능상 좋지 않다)

이런 경우 CTE를 통해 1번만 실행되도록 뽑는 게 좋다. 

 

정답 코드2 (정답 코드1 개선 / CTE 적용)

WITH USER_CTE AS (
    SELECT WRITER_ID 
    FROM USED_GOODS_BOARD
    GROUP BY WRITER_ID 
    HAVING COUNT(*) >= 3
)
SELECT
USER_ID,
NICKNAME,
CONCAT_WS(' ', CITY, STREET_ADDRESS1, STREET_ADDRESS2) 전체주소, 
CONCAT_WS('-', SUBSTRING(TLNO, 1, 3), SUBSTRING(TLNO, 4, 4), SUBSTRING(TLNO, 8, 4)) 전화번호 
FROM USED_GOODS_USER
WHERE USER_ID IN (SELECT * 
                  FROM USER_CTE 
                 )
ORDER BY 1 DESC

 

CTE 적용 완료!!

 

CONCAT_WS() 함수 말고 INSERT() 함수를 사용해서 전화번호 포맷을 바꿔보자 

 

정답 코드3 (정답 코드2 동일 CONCAT_WS → INSERT) 

WITH USER_CTE AS (
    SELECT WRITER_ID 
    FROM USED_GOODS_BOARD
    GROUP BY WRITER_ID 
    HAVING COUNT(*) >= 3
)
SELECT
USER_ID,
NICKNAME,
CONCAT_WS(' ', CITY, STREET_ADDRESS1, STREET_ADDRESS2) 전체주소, 
INSERT(INSERT(TLNO, 8, 0, '-'), 4, 0, '-') 전화번호 
FROM USED_GOODS_USER
WHERE USER_ID IN (SELECT * 
                  FROM USER_CTE 
                 )
ORDER BY 1 DESC