코딩테스트 연습 > String, Date > 조회수가 가장 많은 중고거래 게시판의 첨부파일 조회하기
난이도: Lv.3
언어: MySQL
https://school.programmers.co.kr/learn/courses/30/lessons/164671
실패
SELECT CONCAT('/home/grep/src/', a.BOARD_ID, '/', a.FILE_ID, a.FILE_NAME, a.FILE_EXT) AS FILE_PATH
FROM USED_GOODS_FILE a
WHERE a.BOARD_ID IN
(
SELECT b.BOARD_ID
FROM USED_GOODS_BOARD b
ORDER BY b.VIEWS DESC
LIMIT 1
)
ORDER BY FILE_PATH DESC
성공1-2.에 실패와 관련된 설명이 포함되어있습니다.
성공
성공1.
SELECT CONCAT('/home/grep/src/', a.BOARD_ID, '/', a.FILE_ID, a.FILE_NAME, a.FILE_EXT) AS FILE_PATH
FROM USED_GOODS_FILE a
WHERE a.BOARD_ID IN
(
SELECT *
FROM (
SELECT b.BOARD_ID
FROM USED_GOODS_BOARD b
ORDER BY b.VIEWS DESC
LIMIT 1
) AS c
)
ORDER BY FILE_PATH DESC
우선 채택한 이유는 각 DB에 대해 딱 한번씩 접근하기 때문입니다.
추가적으로 새롭게 알게된 개념이 2가지가 있습니다.
1. CONCAT으로 문자열을 합치는 함수가 존재.
USED_GOODS_FILE 테이블의 각 열들을 하나의 열처럼 합치기 위해서 CONCAT 함수를 이용했습니다.
2. SUBQUERY에 LIMIT을 줄 때는 임시 테이블을 이용해야함. (별칭, Alias, as)
SQL 실행 중 오류가 발생하였습니다.
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SELECT b.BOARD_ID
FROM USED_GOODS_BOARD b
ORDER BY b.VIEWS DESC
' at line 6
WHERE절에서 SUBQUERY사용 시, 임시 테이블을 주지 않으면 위와 같은 에러가 발생합니다.
왜...?? 이해가 가질 않았습니다...
-> 한시간 고민 끝에 .... 찾아냈습니다..!!!
1번 IN은 하나의 행을 나타냄
2번 b.BOARD_ID는 단일 BOARD_ID 하나임
결국 ..... 이렇게 되면 행과 단일 값을 비교할 수가없기 때문에 에러가 계속 발생했던 것으로 판명났습니다..!!!
(우와아ㅏ...)
* SUBQUERY 참고 블로그
https://tttto-factory.tistory.com/entry/MySQL-57-doenst-yet-support-LIMIT-INALLANYSOME-subquery
*참고 chatGPT
MySQL에서 서브쿼리의 LIMIT를 사용할 때 별칭을 주는 이유는 MySQL의 실행 엔진이 서브쿼리를 처리할 때 발생하는 내부적인 동작 방식과 관련이 있습니다. 특히, ORDER BY와 LIMIT를 함께 사용할 때 이러한 제약이 발생합니다.
MySQL은 LIMIT를 사용하는 서브쿼리를 처리할 때, 내부적으로는 임시 테이블을 사용하는 경우가 많습니다. 이 임시 테이블에 대해 MySQL은 일종의 "이름" 또는 "별칭"을 필요로 합니다. 왜냐하면 MySQL은 서브쿼리의 결과를 쿼리에서 참조할 때, 그 결과가 어떤 테이블인지 알아야 하기 때문입니다.
따라서 서브쿼리에 LIMIT를 사용할 때, 해당 서브쿼리에 대해 명시적인 별칭을 주는 것이 좋습니다. 이렇게 하면 MySQL이 내부적으로 생성한 임시 테이블에 이름을 부여하여 정확한 참조를 할 수 있습니다.
실제로 별칭을 주면 MySQL이 서브쿼리를 이해하고 처리할 때 발생하는 문법적인 이슈를 회피할 수 있습니다. 그러므로 MySQL에서는 이러한 작은 문법적인 세부사항을 주의깊게 다뤄야 하는 경우가 있습니다.
성공2.
SELECT CONCAT('/home/grep/src/', a.BOARD_ID, '/', a.FILE_ID, a.FILE_NAME, a.FILE_EXT) AS FILE_PATH
FROM USED_GOODS_FILE a
JOIN USED_GOODS_BOARD b ON a.BOARD_ID = b.BOARD_ID
WHERE b.VIEWS IN
(
SELECT MAX(b.VIEWS)
FROM USED_GOODS_BOARD b
)
ORDER BY FILE_PATH DESC
이 코드는 간결하지만, 실제 DB인 USED_GOODS_BOARD를 2번 접근한다는 점에서 채택하진 않았습니다.
서브쿼리에서 조회수의 최대값을 가져와서 해당 값에 대해 출력하는 코드입니다.
성공3. *채택
성공1 코드가 맘에들지 않아서,, 쓸 곳 없어보이는 SELECT 문이 하나 더 있는 느낌이 들어서,...
더 좋은 코드를 찾아 채택했습니다.
불필요한 SELECT 제거(성공1 보완), DB를 한 번 접근(성공2 보완)한 쿼리입니다.
SELECT CONCAT('/home/grep/src/', a.BOARD_ID, '/', a.FILE_ID, a.FILE_NAME, a.FILE_EXT) AS FILE_PATH
FROM USED_GOODS_FILE a
JOIN (
SELECT *
FROM USED_GOODS_BOARD b
ORDER BY b.VIEWS DESC
LIMIT 1
) c
ON a.BOARD_ID = c.BOARD_ID
ORDER BY FILE_PATH DESC
성공1에서 WHERE 절에 있던 SELECT문을 FROM절로 이동하여 테이블을 JOIN 시켰습니다.
테이블을 JOIN하면서 새로운 임시 테이블인 c를 만들어 좀 더 직관적으로 쿼리를 바꿨습니다.
LIMIT 1로 나오는 결과 테이블(1개의 행)을 c 임시테이블에 저장하고 그 테이블을 a와 비교하는 방법입니다.
성공4.
SELECT CONCAT('/home/grep/src/', a.BOARD_ID, '/', a.FILE_ID, a.FILE_NAME, a.FILE_EXT) AS FILE_PATH
FROM USED_GOODS_FILE a
WHERE a.BOARD_ID =
(
SELECT b.BOARD_ID
FROM USED_GOODS_BOARD b
ORDER BY b.VIEWS DESC
LIMIT 1
)
ORDER BY FILE_PATH DESC
성공1에서 마음에 들지 않던 as c를 삭제하였습니다.
하나의 변수에 대해 비교할 때는 WHERE IN절이아니라 WHERE 변수 = (SELECT~)를 사용하는 것이 더 간단
*참고 chatGPT
'성공1'의 더보기에 기재했습니다.
코드에 질문이 있으시면 댓글을 달아주세요. 최대한 빠른 시일 내에 답변해드리겠습니다.
봐주셔서 감사합니다.
'Study > SQL' 카테고리의 다른 글
[프로그래머스 SQL] 조건에 맞는 사용자와 총 거래금액 조회하기 (0) | 2024.01.16 |
---|---|
[프로그래머스 SQL] 조건별로 분류하여 주문상태 출력하기 (0) | 2024.01.16 |
[프로그래머스 SQL] 헤비 유저가 소유한 장소 (0) | 2024.01.15 |
[프로그래머스 SQL] 있었는데요 없었습니다 (0) | 2024.01.15 |
[프로그래머스 SQL] 오랜 기간 보호한 동물(2) (0) | 2024.01.15 |