<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>mgr100.log</title>
        <link>https://velog.io/</link>
        <description>미래의 독자인 나를 위해 글을 씁니다.</description>
        <lastBuildDate>Wed, 11 Jun 2025 08:16:28 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. mgr100.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/mgr_baek" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[SQL] 특정 세대의 대장균 찾기]]></title>
            <link>https://velog.io/@mgr_baek/SQL-%ED%8A%B9%EC%A0%95-%EC%84%B8%EB%8C%80%EC%9D%98-%EB%8C%80%EC%9E%A5%EA%B7%A0-%EC%B0%BE%EA%B8%B0</link>
            <guid>https://velog.io/@mgr_baek/SQL-%ED%8A%B9%EC%A0%95-%EC%84%B8%EB%8C%80%EC%9D%98-%EB%8C%80%EC%9E%A5%EA%B7%A0-%EC%B0%BE%EA%B8%B0</guid>
            <pubDate>Wed, 11 Jun 2025 08:16:28 GMT</pubDate>
            <description><![CDATA[<h2 id="🔎-문제설명">🔎 문제설명</h2>
<ul>
<li>출처: <a href="https://school.programmers.co.kr/learn/courses/30/lessons/301650">프로그래머스</a></li>
<li>사용언어(RDBMS): SQL(MySQL)</li>
<li>문제:<blockquote>
<p>3세대의 대장균의 ID(ID) 를 출력하는 SQL 문을 작성해주세요. 이때 결과는 대장균의 ID 에 대해 오름차순 정렬해주세요.</p>
</blockquote>
</li>
</ul>
<br>
<br>
<br>

<h2 id="✅-제출답안">✅ 제출답안</h2>
<pre><code class="language-sql"># 재귀CTE를 사용하지 않은 방법
# 테이블 별로 ID의 의미: ONE이 1세대, TWO가 2세대, THREE가 3세대
SELECT THREE.ID
FROM ECOLI_DATA AS ONE 
    JOIN ECOLI_DATA AS TWO ON (ONE.ID = TWO.PARENT_ID AND ONE.PARENT_ID IS NULL)
    JOIN ECOLI_DATA AS THREE ON TWO.ID = THREE.PARENT_ID
ORDER BY 1;</code></pre>
<pre><code class="language-sql"># 재귀CTE를 사용한 답안
WITH RECURSIVE GEN_E AS (
    # 1세대 대장균
    SELECT ID, 1 AS GEN
    FROM ECOLI_DATA 
    WHERE PARENT_ID IS NULL

    UNION ALL
    # 2세대부터의 대장균
    SELECT E.ID, GEN + 1
    FROM ECOLI_DATA E INNER JOIN GEN_E P ON E.PARENT_ID = P.ID
)
SELECT ID
FROM GEN_E
WHERE GEN = 3       # 3세대의 대장균만 추출
ORDER BY 1;</code></pre>
<br>
<br>
<br>

<h2 id="🚀-풀이기록">🚀 풀이기록</h2>
<p><em>3세대의 대장균을 추출하는 문제여서 JOIN을 두 번 사용하면 풀 수 있는 문제였다. 그런데 문제의 의도는 재귀CTE를 사용하는 것 같아, 이후에 다시 문제를 풀었을 때는 재귀CTE방법을 사용했다.</em> </p>
<h3 id="주의할-점">주의할 점</h3>
<ul>
<li>1세대 대장균을 추출할 때 <code>PARENT_ID</code>가 <code>NULL</code>이라는 조건을 걸어주는 걸 잊지 말아야 한다. 그래야 2세대, 3세대 대장균도 제대로 추출할 수 있다!</li>
</ul>
<h3 id="재귀cte">재귀CTE</h3>
<ul>
<li><p>재귀CTE를 사용하여 전 세대의 대장균을 추출했다. </p>
</li>
<li><p>몇 세대인지 표시하기 위해 <code>GEN</code>컬럼에 몇 세대인지 표시하게 했다.</p>
<pre><code class="language-sql">WITH RECURSIVE GEN_E AS (
  # 1세대 대장균
  SELECT ID, 1 AS GEN
  FROM ECOLI_DATA 
  WHERE PARENT_ID IS NULL

  UNION ALL
  # 2세대부터의 대장균
  SELECT E.ID, GEN + 1
  FROM ECOLI_DATA E INNER JOIN GEN_E P ON E.PARENT_ID = P.ID
)</code></pre>
<p>이후 <code>WHERE</code>에 조건을 걸어 3세대 대장균만 추출한 뒤, <code>ID</code>로 오름차순 정렬을 했다.</p>
<pre><code class="language-sql">SELECT ID
FROM GEN_E
WHERE GEN = 3       # 3세대의 대장균만 추출
ORDER BY 1;</code></pre>
</li>
</ul>
<p>처음에는 코드에 자세한 설명을 쓰려다가, 생각해보니 이 부분은 익숙해져야 하는 부분이라 간단히 메모만 해놓았다. 설명을 써놓는 것보다 나중에 다시 문제를 풀게 될 때 코드를 따라쓰는게 더 도움이 될 거 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] 입양 시각 구하기(2)]]></title>
            <link>https://velog.io/@mgr_baek/SQL-%EC%9E%85%EC%96%91-%EC%8B%9C%EA%B0%81-%EA%B5%AC%ED%95%98%EA%B8%B02</link>
            <guid>https://velog.io/@mgr_baek/SQL-%EC%9E%85%EC%96%91-%EC%8B%9C%EA%B0%81-%EA%B5%AC%ED%95%98%EA%B8%B02</guid>
            <pubDate>Wed, 11 Jun 2025 07:40:51 GMT</pubDate>
            <description><![CDATA[<h2 id="🔎-문제설명">🔎 문제설명</h2>
<ul>
<li>출처: <a href="https://school.programmers.co.kr/learn/courses/30/lessons/59413">프로그래머스</a></li>
<li>사용언어(RDBMS): SQL(MySQL)</li>
<li>문제:<blockquote>
<p>보호소에서는 몇 시에 입양이 가장 활발하게 일어나는지 알아보려 합니다. 0시부터 23시까지, 각 시간대별로 입양이 몇 건이나 발생했는지 조회하는 SQL문을 작성해주세요. 이때 결과는 시간대 순으로 정렬해야 합니다.</p>
</blockquote>
</li>
</ul>
<br>
<br>
<br>

<h2 id="✅-제출답안">✅ 제출답안</h2>
<pre><code class="language-sql"># 재귀CTE를 이용한 답안
WITH RECURSIVE TIME AS (
  SELECT 0 AS HOUR
  UNION ALL

  SELECT HOUR + 1
  FROM TIME
  WHERE HOUR &lt; 23
),
COUNT_BY_HOUR AS (
    SELECT HOUR(DATETIME) AS HOUR,
           COUNT(ANIMAL_ID) AS COUNT
    FROM ANIMAL_OUTS
    GROUP BY HOUR(DATETIME)
)
SELECT HOUR, IFNULL(COUNT, 0) AS COUNT
FROM COUNT_BY_HOUR AS A RIGHT JOIN TIME AS B USING(HOUR)
ORDER BY HOUR</code></pre>
<br>
<br>
<br>

<h2 id="🚀-풀이기록">🚀 풀이기록</h2>
<p>이 문제의 의도는 재귀적 방법을 사용하여 풀도록 하려고 했던 거 같다. 다시 풀려고 하니 기억이 나지 않아 지난번에 기록했던 내용을 옮겨놓는 데에 의의를 두려고 한다.</p>
<ul>
<li>재귀CTE(Common Table Expression) 참고: <a href="https://www.mysqltutorial.org/mysql-basics/mysql-recursive-cte/">Recursive CTE</a></li>
</ul>
<h3 id="재귀cte를-사용하지-않고-group-by를-사용하여-쿼리를-작성하는-경우">재귀CTE를 사용하지 않고 GROUP BY를 사용하여 쿼리를 작성하는 경우</h3>
<blockquote>
<p>문제에서는 0시부터 23시까지의 입양된 동물의 수를 표시하고 싶지만, 테이블에서 특정시간대에 입양된 동물이 존재하지 않는 경우는 그 시각이 나타나지 않는다(아래 이미지에서는 가장 빠른 시간이 0시가 아닌 7시이다.).
<img src="https://velog.velcdn.com/images/mgr_baek/post/70c6777f-37de-49e7-9a53-721f0d67788d/image.png" alt=""></p>
</blockquote>
<p>따라서 입양이 이루어지지 않은 시간도 나타내기 위해서는, 일일이 숫자를 0부터 23까지 일일이 써줄수 있으나 이건 너무 비효율적이다. 내 머리로는 해결할 수 없는 문제라고 판단하고 다른 분들의 답을 확인했다. 다른 분들은 재귀CTE(Recursive CTE)방법을 사용했다고 하는데 코드를 봐도 잘 이해가 안가서 GPT에게 도움을 요청했다.</p>
<h3 id="재귀cte의-장점">재귀CTE의 장점</h3>
<ul>
<li>재귀적인 방식으로 숫자를 생성하므로, 추가적인 JOIN이나 복잡한 쿼리를 사용하지 않고 간단하게 시퀀스를 만들 수 있음.</li>
<li><code>WHERE</code> 조건을 조정하여 원하는 범위의 숫자만 생성 가능.</li>
</ul>
<h3 id="재귀-cte를-사용한-숫자-생성">재귀 CTE를 사용한 숫자 생성</h3>
<pre><code class="language-sql">WITH RECURSIVE NUMBERS AS (
  SELECT 0 AS NUMBER
  UNION ALL
  SELECT NUMBER + 1
  FROM NUMBERS
  WHERE NUMBER &lt; 23
)
SELECT NUMBER FROM NUMBERS;</code></pre>
<ol>
<li><code>WITH RECURSIVE NUMBERS AS (...)</code>: <code>NUMBERS</code>라는 이름의 재귀CTE를 정의</li>
<li><code>SELECT 0 AS NUMBER</code>: 재귀의 시작값으로 0을 설정</li>
<li><code>UNION ALL</code>: 재귀적으로 값을 생성. 첫번째 <code>SELECT</code>는 0을 반환하고, 두 번째 <code>SELECT</code>는 이전 <code>NUMBER</code>에 1을 더하여 숫자를 증가시킴</li>
<li><code>WHERE NUMBER &lt; 23</code>: <code>NUMBER</code>가 23보다 작은 값일 때만 재귀를 계속 수행</li>
<li><code>SELECT NUMBER FROM NUMBERS;</code>: <code>NUMBERS</code>CTE에서 생성된 숫자를 결과로 반환
=&gt; 해당 쿼리는 0부터 23까지의 숫자 리스트를 반환</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] 그룹별 조건에 맞는 식당 목록 출력하기]]></title>
            <link>https://velog.io/@mgr_baek/SQL-%EA%B7%B8%EB%A3%B9%EB%B3%84-%EC%A1%B0%EA%B1%B4%EC%97%90-%EB%A7%9E%EB%8A%94-%EC%8B%9D%EB%8B%B9-%EB%AA%A9%EB%A1%9D-%EC%B6%9C%EB%A0%A5%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@mgr_baek/SQL-%EA%B7%B8%EB%A3%B9%EB%B3%84-%EC%A1%B0%EA%B1%B4%EC%97%90-%EB%A7%9E%EB%8A%94-%EC%8B%9D%EB%8B%B9-%EB%AA%A9%EB%A1%9D-%EC%B6%9C%EB%A0%A5%ED%95%98%EA%B8%B0</guid>
            <pubDate>Wed, 11 Jun 2025 06:52:38 GMT</pubDate>
            <description><![CDATA[<h2 id="🔎-문제설명">🔎 문제설명</h2>
<ul>
<li>출처: <a href="https://school.programmers.co.kr/learn/courses/30/lessons/131124">프로그래머스</a></li>
<li>사용언어(RDBMS): SQL(MySQL)</li>
<li>문제:<blockquote>
<p><code>MEMBER_PROFILE</code>와 <code>REST_REVIEW</code> 테이블에서 리뷰를 가장 많이 작성한 회원의 리뷰들을 조회하는 SQL문을 작성해주세요. 회원 이름, 리뷰 텍스트, 리뷰 작성일이 출력되도록 작성해주시고, 결과는 리뷰 작성일을 기준으로 오름차순, 리뷰 작성일이 같다면 리뷰 텍스트를 기준으로 오름차순 정렬해주세요.</p>
</blockquote>
</li>
</ul>
<br>
<br>
<br>

<h2 id="✅-제출답안">✅ 제출답안</h2>
<pre><code class="language-sql"># 처음 작성한 답안 - Limit사용(권장x)
SELECT MEMBER_NAME, REVIEW_TEXT, DATE_FORMAT(REVIEW_DATE, &quot;%Y-%m-%d&quot;) AS REVIEW_DATE
FROM REST_REVIEW AS R JOIN MEMBER_PROFILE AS P USING(MEMBER_ID)
WHERE MEMBER_ID = (SELECT MEMBER_ID
              FROM REST_REVIEW
              GROUP BY MEMBER_ID
              ORDER BY COUNT(REVIEW_ID) DESC
              LIMIT 1 )
ORDER BY REVIEW_DATE, REVIEW_TEXT</code></pre>
<pre><code class="language-sql"># 다시 풀었을 때 작성한 답안
# 최다리뷰자가 여러명일 경우를 고려 - RANK() 사용(권장)
WITH DEVOTED_REVIEWER AS (
  SELECT MEMBER_ID,
         RANK() OVER (ORDER BY COUNT(REVIEW_ID) DESC) AS REVIEW_RANK
  FROM REST_REVIEW
  GROUP BY MEMBER_ID

)
SELECT M.MEMBER_NAME, 
       R.REVIEW_TEXT, 
       DATE_FORMAT(R.REVIEW_DATE, &#39;%Y-%m-%d&#39;) AS REVIEW_DATE
FROM DEVOTED_REVIEWER D JOIN MEMBER_PROFILE M USING(MEMBER_ID)
     JOIN REST_REVIEW R USING(MEMBER_ID)
WHERE D.REVIEW_RANK = 1
ORDER BY 3, 2;</code></pre>
<br>
<br>
<br>

<h2 id="🚀-풀이기록">🚀 풀이기록</h2>
<p>처음 이 문제를 풀었을 때, 최다리뷰 작성자를 필터링 하기 위해 회원별로 작성한 리뷰수를 내림차순으로 정렬해서 <code>Limit</code>를 사용하여 1명의 회원만 추출하게 했다. 코드 실행도 잘되었고 제출 했을 때 정답처리도 되었다. 하지만 생각해보면 최다리뷰 작성자는 여러명일 수 있다. 실제로 문제에서 최다리뷰 작성자를 조회해본 결과, 결과는 아래와 같이 3명의 공동 최다리뷰작성자가 있음을 확인했다.
<img src="https://velog.velcdn.com/images/mgr_baek/post/676cd621-936a-48c8-830e-ae137550258b/image.png" alt="">
정답처리가 되었지만 나중에 다시 풀어볼 때는 <code>RANK()</code>를 사용하여 리뷰수가 많은 순으로 정렬한 뒤 순위가 1인 행만 추출하는 방식으로 해야겠다고 생각했다.
시간이 지난 뒤 다시 문제를 풀면서 with문을 사용해 회원별로 남긴 리뷰수에 따라 순위를 매긴 임시 테이블을 만들어주고, 최종 테이블과 결합해서 순위가 1인 회원만 추출했다.</p>
<pre><code class="language-sql">WHERE D.REVIEW_RANK = 1</code></pre>
<p>그 결과 아래와 같이 3명의 리뷰작성내역이 나왔고, 제출결과 정답처리 되었다.
<img src="https://velog.velcdn.com/images/mgr_baek/post/a1e7ab99-52af-4267-b34c-6fc3932fd57c/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] 연간 평가점수에 해당하는 평가 등급 및 성과금 조회하기]]></title>
            <link>https://velog.io/@mgr_baek/SQL-%EC%97%B0%EA%B0%84-%ED%8F%89%EA%B0%80%EC%A0%90%EC%88%98%EC%97%90-%ED%95%B4%EB%8B%B9%ED%95%98%EB%8A%94-%ED%8F%89%EA%B0%80-%EB%93%B1%EA%B8%89-%EB%B0%8F-%EC%84%B1%EA%B3%BC%EA%B8%88-%EC%A1%B0%ED%9A%8C%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@mgr_baek/SQL-%EC%97%B0%EA%B0%84-%ED%8F%89%EA%B0%80%EC%A0%90%EC%88%98%EC%97%90-%ED%95%B4%EB%8B%B9%ED%95%98%EB%8A%94-%ED%8F%89%EA%B0%80-%EB%93%B1%EA%B8%89-%EB%B0%8F-%EC%84%B1%EA%B3%BC%EA%B8%88-%EC%A1%B0%ED%9A%8C%ED%95%98%EA%B8%B0</guid>
            <pubDate>Wed, 11 Jun 2025 06:05:42 GMT</pubDate>
            <description><![CDATA[<h2 id="🔎-문제설명">🔎 문제설명</h2>
<ul>
<li>출처: <a href="https://school.programmers.co.kr/learn/courses/30/lessons/284528">프로그래머스</a></li>
<li>사용언어(RDBMS): SQL(MySQL)</li>
<li>문제:<blockquote>
<p><code>HR_DEPARTMENT</code>, <code>HR_EMPLOYEES</code>, <code>HR_GRADE</code> 테이블을 이용해 사원별 성과금 정보를 조회하려합니다. 평가 점수별 등급과 등급에 따른 성과금 정보가 아래와 같을 때, 사번, 성명, 평가 등급, 성과금을 조회하는 SQL문을 작성해주세요.
평가등급의 컬럼명은 GRADE로, 성과금의 컬럼명은 BONUS로 해주세요.
결과는 사번 기준으로 오름차순 정렬해주세요.</p>
</blockquote>
</li>
</ul>
<br>
<br>
<br>

<h2 id="✅-제출답안">✅ 제출답안</h2>
<pre><code class="language-sql">WITH YEAR_GRADE AS (
    SELECT EMP_NO, 
           CASE WHEN AVG(SCORE) &gt;= 96 THEN &#39;S&#39;
                WHEN AVG(SCORE) &gt;= 90 THEN &#39;A&#39;
                WHEN AVG(SCORE) &gt;= 80 THEN &#39;B&#39;
           ELSE &#39;C&#39; END AS GRADE
    FROM HR_GRADE
    GROUP BY EMP_NO, YEAR
)
SELECT EMP_NO,
       EMP_NAME,
       G.GRADE,
       CASE WHEN G.GRADE = &#39;S&#39; THEN H.SAL*0.2
            WHEN G.GRADE = &#39;A&#39; THEN H.SAL*0.15
            WHEN G.GRADE = &#39;B&#39; THEN H.SAL*0.1
       ELSE 0 END AS BONUS
FROM YEAR_GRADE G JOIN HR_EMPLOYEES H USING(EMP_NO)
ORDER BY 1;

</code></pre>
<br>
<br>
<br>

<h2 id="🚀-풀이기록">🚀 풀이기록</h2>
<p>문제에서는 <code>GRADE</code>테이블의 평가점수가 반기(half year)별로 나와있다. 해당 해의 평가점수를 구하기 위해서는 상반기와 하반기의 점수를 평균내야 한다. 이전에 같은 테이블을 이용한 다른 문제에서는 명시되어 있었는데 여기서는 명시되어 있지 않은 게 약간 아쉬웠다. 그 점을 제외하고는 무난하게 풀 수 있었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] 년, 월, 성별 별 상품 구매 회원 수 구하기]]></title>
            <link>https://velog.io/@mgr_baek/SQL-%EB%85%84-%EC%9B%94-%EC%84%B1%EB%B3%84-%EB%B3%84-%EC%83%81%ED%92%88-%EA%B5%AC%EB%A7%A4-%ED%9A%8C%EC%9B%90-%EC%88%98-%EA%B5%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@mgr_baek/SQL-%EB%85%84-%EC%9B%94-%EC%84%B1%EB%B3%84-%EB%B3%84-%EC%83%81%ED%92%88-%EA%B5%AC%EB%A7%A4-%ED%9A%8C%EC%9B%90-%EC%88%98-%EA%B5%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Wed, 11 Jun 2025 05:21:47 GMT</pubDate>
            <description><![CDATA[<h2 id="🔎-문제설명">🔎 문제설명</h2>
<ul>
<li>출처: <a href="https://school.programmers.co.kr/learn/courses/30/lessons/131532">프로그래머스</a></li>
<li>사용언어(RDBMS): SQL(MySQL)</li>
<li>문제:<blockquote>
<p><code>USER_INFO</code> 테이블과 <code>ONLINE_SALE</code> 테이블에서 년, 월, 성별 별로 상품을 구매한 회원수를 집계하는 SQL문을 작성해주세요. 결과는 년, 월, 성별을 기준으로 오름차순 정렬해주세요. 이때, 성별 정보가 없는 경우 결과에서 제외해주세요.</p>
</blockquote>
</li>
</ul>
<br>
<br>
<br>

<h2 id="✅-제출답안">✅ 제출답안</h2>
<pre><code class="language-sql">SELECT YEAR(SALES_DATE) AS YEAR, 
       MONTH(SALES_DATE) AS MONTH, 
       GENDER,
       COUNT(DISTINCT USER_ID) AS USERS
FROM USER_INFO AS I JOIN ONLINE_SALE AS O
USING(USER_ID)
WHERE GENDER IS NOT NULL
GROUP BY YEAR(SALES_DATE), MONTH(SALES_DATE), GENDER
ORDER BY 1, 2, 3

</code></pre>
<br>
<br>
<br>

<h2 id="🚀-풀이기록">🚀 풀이기록</h2>
<p>회원수(<code>USERS</code>)를 구할 때 <code>DISTINCT</code>를 사용하여 같은 달에 여러 번 구매한 회원이 중복되게 계산되지 않도록 한다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] 식품분류별 가장 비싼 식품의 정보 조회하기]]></title>
            <link>https://velog.io/@mgr_baek/SQL-%EC%8B%9D%ED%92%88%EB%B6%84%EB%A5%98%EB%B3%84-%EA%B0%80%EC%9E%A5-%EB%B9%84%EC%8B%BC-%EC%8B%9D%ED%92%88%EC%9D%98-%EC%A0%95%EB%B3%B4-%EC%A1%B0%ED%9A%8C%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@mgr_baek/SQL-%EC%8B%9D%ED%92%88%EB%B6%84%EB%A5%98%EB%B3%84-%EA%B0%80%EC%9E%A5-%EB%B9%84%EC%8B%BC-%EC%8B%9D%ED%92%88%EC%9D%98-%EC%A0%95%EB%B3%B4-%EC%A1%B0%ED%9A%8C%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 10 Jun 2025 18:00:05 GMT</pubDate>
            <description><![CDATA[<h2 id="🔎-문제설명">🔎 문제설명</h2>
<ul>
<li>출처: <a href="https://school.programmers.co.kr/learn/courses/30/lessons/131116">프로그래머스</a></li>
<li>사용언어(RDBMS): SQL(MySQL)</li>
<li>문제:<blockquote>
<p><code>FOOD_PRODUCT</code> 테이블에서 식품분류별로 가격이 제일 비싼 식품의 분류, 가격, 이름을 조회하는 SQL문을 작성해주세요. 이때 식품분류가 &#39;과자&#39;, &#39;국&#39;, &#39;김치&#39;, &#39;식용유&#39;인 경우만 출력시켜 주시고 결과는 식품 가격을 기준으로 내림차순 정렬해주세요.</p>
</blockquote>
</li>
</ul>
<br>
<br>
<br>

<h2 id="✅-제출답안">✅ 제출답안</h2>
<pre><code class="language-sql">SELECT CATEGORY, PRICE AS MAX_PRICE, PRODUCT_NAME
FROM FOOD_PRODUCT
WHERE CATEGORY IN (&#39;과자&#39;, &#39;국&#39;, &#39;김치&#39;, &#39;식용유&#39;)
      AND (CATEGORY, PRICE) IN (SELECT CATEGORY, MAX(PRICE)
                               FROM FOOD_PRODUCT
                               GROUP BY CATEGORY)
ORDER BY 2 DESC;</code></pre>
<br>
<br>
<br>

<h2 id="🚀-풀이기록">🚀 풀이기록</h2>
<p>이 쿼리문을 작성할 때 주의할 점이 where문을 거치지 않고 바로 SELECT문에서 MAX()함수를 써서 가장 비싼 가격과 식품 이름을 추출하려는 실수를 범하는 것이다. 만약 아래 코드처럼</p>
<pre><code class="language-sql">WHERE CATEGORY IN (&#39;과자&#39;, &#39;국&#39;, &#39;김치&#39;, &#39;식용유&#39;)
      AND (CATEGORY, PRICE) IN (SELECT CATEGORY, MAX(PRICE)
                               FROM FOOD_PRODUCT
                               GROUP BY CATEGORY)</code></pre>
<p>where문에 <code>(CATEGORY, PRICE)</code>로 묶어서 식품 분류와 가장 비싼 가격을 쌍을 지어 조건을 넣어주지 않으면, SELECT문에서 PRODUCT_NAME에는 어떤 행의 <code>PRODUCT_NAME</code>이 올지 정의되지 않거나 예측 불가능한 결과가 나올 수 있다.Gemini에 따르면 대부분의 데이터베이스에서는 해당 그룹의 &#39;첫 번째&#39; 또는 &#39;임의의&#39; <code>PRODUCT_NAME</code>을 반환하게 된다고 한다.</p>
<ul>
<li>Gemini가 제안해준 코드<ul>
<li>대규모 데이터셋에서는 JOIN을 사용하여 <code>GROUP BY</code>또는 윈도우 함수를 사용하는 것이 더 효율적이라는 제안을 해주었다.<ul>
<li>이 쿼리문은 각 카테고리별로 가격이 높은 순서대로 순위를 매기고, 순위가 1인 (가장 비싼) 제품만 선택해서 추출한다.
```sql</li>
</ul>
</li>
</ul>
</li>
<li><ul>
<li>Window Function (ROW_NUMBER() 또는 RANK() 사용)
SELECT CATEGORY, PRICE AS MAX_PRICE, PRODUCT_NAME
FROM (
 SELECT<pre><code> CATEGORY,
 PRICE,
 PRODUCT_NAME,
 ROW_NUMBER() OVER (PARTITION BY CATEGORY ORDER BY PRICE DESC) as rn</code></pre> FROM FOOD_PRODUCT
 WHERE CATEGORY IN (&#39;과자&#39;, &#39;국&#39;, &#39;김치&#39;, &#39;식용유&#39;)
) AS SubQuery
WHERE rn = 1
ORDER BY MAX_PRICE DESC;
```</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] 대장균의 크기에 따라 분류하기 2]]></title>
            <link>https://velog.io/@mgr_baek/SQL-%EB%8C%80%EC%9E%A5%EA%B7%A0%EC%9D%98-%ED%81%AC%EA%B8%B0%EC%97%90-%EB%94%B0%EB%9D%BC-%EB%B6%84%EB%A5%98%ED%95%98%EA%B8%B0-2</link>
            <guid>https://velog.io/@mgr_baek/SQL-%EB%8C%80%EC%9E%A5%EA%B7%A0%EC%9D%98-%ED%81%AC%EA%B8%B0%EC%97%90-%EB%94%B0%EB%9D%BC-%EB%B6%84%EB%A5%98%ED%95%98%EA%B8%B0-2</guid>
            <pubDate>Tue, 10 Jun 2025 17:27:10 GMT</pubDate>
            <description><![CDATA[<h2 id="🔎-문제설명">🔎 문제설명</h2>
<ul>
<li>출처: <a href="https://school.programmers.co.kr/learn/courses/30/lessons/301649">프로그래머스</a></li>
<li>사용언어(RDBMS): SQL(MySQL)</li>
<li>문제:<blockquote>
<p>대장균 개체의 크기를 내림차순으로 정렬했을 때 상위 0% ~ 25% 를 &#39;CRITICAL&#39;, 26% ~ 50% 를 &#39;HIGH&#39;, 51% ~ 75% 를 &#39;MEDIUM&#39;, 76% ~ 100% 를 &#39;LOW&#39; 라고 분류합니다. 대장균 개체의 ID(ID) 와 분류된 이름(COLONY_NAME)을 출력하는 SQL 문을 작성해주세요. 이때 결과는 개체의 ID 에 대해 오름차순 정렬해주세요 . 단, 총 데이터의 수는 4의 배수이며 같은 사이즈의 대장균 개체가 서로 다른 이름으로 분류되는 경우는 없습니다.</p>
</blockquote>
</li>
</ul>
<br>
<br>
<br>

<h2 id="✅-제출답안">✅ 제출답안</h2>
<pre><code class="language-sql">SELECT ID, 
       CASE WHEN DEGREE = 1 THEN &quot;CRITICAL&quot;
            WHEN DEGREE = 2 THEN &quot;HIGH&quot;
            WHEN DEGREE = 3 THEN &quot;MEDIUM&quot;
            WHEN DEGREE = 4 THEN &quot;LOW&quot;
        END AS COLONY_NAME
FROM (SELECT ID, NTILE(4) OVER (ORDER BY SIZE_OF_COLONY DESC) AS DEGREE
     FROM ECOLI_DATA) AS E
ORDER BY ID ASC;</code></pre>
<br>
<br>
<br>

<h2 id="🚀-풀이기록">🚀 풀이기록</h2>
<p>처음 문제를 접했을 때 대장균 개체의 크기를 내림차순으로 정렬했을 때 어떻게 4등분으로 나누어 이름을 붙일지를 고민했다. 윈도우 함수를 가장 먼저 떠올렸으나 정말 기억이 안났다... </p>
<ul>
<li><p>window 함수 참고: <a href="https://www.mysqltutorial.org/mysql-window-functions/">MySQL Window Functions</a></p>
</li>
<li><p>전체 데이터에 대해 이름을 분류하므로 <strong><code>PARTITION BY</code>를 사용하지 않았다.</strong></p>
</li>
<li><p>내림차순으로 정렬해 숫자를 비교하므로 <strong><code>ORDER BY 컬럼명 DESC</code></strong>사용</p>
</li>
<li><p>또 이것을 25%, 50%, 75%, 100%로 4개의 구간으로 나누어서 분류하므로 <strong><code>NTILE(4)</code></strong>로 작성</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] 자동차 대여 기록에서 대여중 / 대여 가능 여부 구분하기]]></title>
            <link>https://velog.io/@mgr_baek/SQL-%EC%9E%90%EB%8F%99%EC%B0%A8-%EB%8C%80%EC%97%AC-%EA%B8%B0%EB%A1%9D%EC%97%90%EC%84%9C-%EB%8C%80%EC%97%AC%EC%A4%91-%EB%8C%80%EC%97%AC-%EA%B0%80%EB%8A%A5-%EC%97%AC%EB%B6%80-%EA%B5%AC%EB%B6%84%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@mgr_baek/SQL-%EC%9E%90%EB%8F%99%EC%B0%A8-%EB%8C%80%EC%97%AC-%EA%B8%B0%EB%A1%9D%EC%97%90%EC%84%9C-%EB%8C%80%EC%97%AC%EC%A4%91-%EB%8C%80%EC%97%AC-%EA%B0%80%EB%8A%A5-%EC%97%AC%EB%B6%80-%EA%B5%AC%EB%B6%84%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 10 Jun 2025 16:30:41 GMT</pubDate>
            <description><![CDATA[<h2 id="🔎-문제설명">🔎 문제설명</h2>
<ul>
<li>출처: <a href="https://school.programmers.co.kr/learn/courses/30/lessons/157340">프로그래머스</a></li>
<li>사용언어(RDBMS): SQL(MySQL)</li>
<li>문제:<blockquote>
<p><code>CAR_RENTAL_COMPANY_RENTAL_HISTORY</code> 테이블에서 2022년 10월 16일에 대여 중인 자동차인 경우 &#39;대여중&#39; 이라고 표시하고, 대여 중이지 않은 자동차인 경우 &#39;대여 가능&#39;을 표시하는 컬럼(컬럼명: AVAILABILITY)을 추가하여 자동차 ID와 AVAILABILITY 리스트를 출력하는 SQL문을 작성해주세요. 이때 반납 날짜가 2022년 10월 16일인 경우에도 &#39;대여중&#39;으로 표시해주시고 결과는 자동차 ID를 기준으로 내림차순 정렬해주세요.</p>
</blockquote>
</li>
</ul>
<br>
<br>
<br>

<h2 id="✅-제출답안">✅ 제출답안</h2>
<pre><code class="language-sql"># 답안1 - 처음 풀었을 때(다른 풀이 참고)
SELECT CAR_ID, 
       CASE WHEN MAX(&#39;2022-10-16&#39; BETWEEN START_DATE AND END_DATE) THEN &#39;대여중&#39;
            ELSE &#39;대여 가능&#39;
    END AS AVAILABILITY
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY 
GROUP BY CAR_ID
ORDER BY CAR_ID DESC;</code></pre>
<pre><code class="language-sql"># 답안2 - 다시 풀었을 때 
SELECT CAR_ID,
       IF(SUM(AVAILABILITY) = 0, &#39;대여 가능&#39;, &#39;대여중&#39;) AS AVAILABILITY
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY H JOIN (SELECT CAR_ID, IF(START_DATE &lt;= &#39;2022-10-16&#39; AND END_DATE &gt;= &#39;2022-10-16&#39;, 1, 0) AS AVAILABILITY
                                               FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
                                            ) A USING(CAR_ID)
GROUP BY CAR_ID
ORDER BY CAR_ID DESC;</code></pre>
<br>
<br>
<br>

<h2 id="🚀-풀이기록">🚀 풀이기록</h2>
<h3 id="1-답안1">1. 답안1</h3>
<pre><code class="language-sql">CASE WHEN MAX(&#39;2022-10-16&#39; BETWEEN START_DATE AND END_DATE) 
     THEN &#39;대여중&#39; ELSE &#39;대여 가능&#39; END AS AVAILABILITY</code></pre>
<p>START_DATE와 END_DATE 사이에 2022년 10월 16일이 있는지 여부에 따라 대여중과 대여 가능으로 나뉜다. 만약에 CAR_ID가 1인 자동차에 대해 <code>AVAILABILITY</code>속성의 값이 ‘대여중’인 행과 ‘대여 가능’행이 모두 존재할 수 있다. 이런 경우, 2022-10-16에 대여가 되었다는 것이므로, <code>MAX()</code>를 사용해 AVAILABILITY속성이 <strong><code>대여 가능</code></strong> 값이 나오도록 출력해줘야 한다.</p>
<ul>
<li><strong><code>대여 가능</code></strong> 을 써줄 때 꼭 띄어쓰기 하자. 안하면 틀린다.</li>
</ul>
<h3 id="2-답안2">2. 답안2</h3>
<pre><code class="language-sql">...
SELECT CAR_ID, 
       IF(START_DATE &lt;= &#39;2022-10-16&#39; AND END_DATE &gt;= &#39;2022-10-16&#39;, 1, 0) AS AVAILABILITY
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
...                                    </code></pre>
<p>JOIN을 쓰지 않고 바로 GROUP BY문을 사용해서 쿼리를 작성하고 싶었다. 그런데 2022년 10월 16일에 대여중이라는 사실을 알려면 행마다 대여가능표시를 해야할 거 같아, 각 행마다 만약 대여중인 경우는 1, 그렇지 않은 경우는 0을 표시한 컬럼(AVAILABILITY)을 추가해 JOIN을 해주었다. JOIN 후 CAR_ID별로 묶어준 뒤 만약 대여가능여부(AVAILABILITY) 컬럼의 합이 1이상이면 <code>대여중</code>, 그렇지 않으면 <code>대여 가능</code>으로 표시되게 했다.</p>
<p>답안1이 조인을 사용하지 않고, 연산이 더 적어 더 좋은 쿼리문인 거 같다. 근데 막상 문제 풀면 저렇게 안된단말이지...</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] 조건에 맞는 사용자 정보 조회하기]]></title>
            <link>https://velog.io/@mgr_baek/SQL-%EC%A1%B0%EA%B1%B4%EC%97%90-%EB%A7%9E%EB%8A%94-%EC%82%AC%EC%9A%A9%EC%9E%90-%EC%A0%95%EB%B3%B4-%EC%A1%B0%ED%9A%8C%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@mgr_baek/SQL-%EC%A1%B0%EA%B1%B4%EC%97%90-%EB%A7%9E%EB%8A%94-%EC%82%AC%EC%9A%A9%EC%9E%90-%EC%A0%95%EB%B3%B4-%EC%A1%B0%ED%9A%8C%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 10 Jun 2025 15:38:23 GMT</pubDate>
            <description><![CDATA[<h2 id="🔎-문제설명">🔎 문제설명</h2>
<ul>
<li>출처: <a href="https://school.programmers.co.kr/learn/courses/30/lessons/164670">프로그래머스</a></li>
<li>사용언어(RDBMS): SQL(MySQL)</li>
<li>문제:<blockquote>
<p>USED_GOODS_BOARD와 USED_GOODS_USER 테이블에서 중고 거래 게시물을 3건 이상 등록한 사용자의 사용자 ID, 닉네임, 전체주소, 전화번호를 조회하는 SQL문을 작성해주세요. 이때, 전체 주소는 시, 도로명 주소, 상세 주소가 함께 출력되도록 해주시고, 전화번호의 경우 xxx-xxxx-xxxx 같은 형태로 하이픈 문자열(-)을 삽입하여 출력해주세요. 결과는 회원 ID를 기준으로 내림차순 정렬해주세요.</p>
</blockquote>
</li>
</ul>
<br>
<br>
<br>

<h2 id="✅-제출답안">✅ 제출답안</h2>
<pre><code class="language-sql"># user관련 테이블의 컬럼을 문제에 맞게 전처리
WITH PREPROCESSED AS (
    SELECT USER_ID, NICKNAME, 
            CONCAT(CITY,&#39; &#39;, STREET_ADDRESS1,&#39; &#39;, STREET_ADDRESS2) AS TOTAL_ADDRESS,
            CONCAT(SUBSTRING(TLNO,1, 3),&quot;-&quot;,
                   SUBSTRING(TLNO,4, 4),&quot;-&quot;,
                   SUBSTRING(TLNO,8, 4)) AS TLNO

    FROM USED_GOODS_USER
)

# 조인 후 게시판에 올린 글의 개수가 3개이상인 경우만 추출
SELECT PP.USER_ID, PP.NICKNAME, PP.TOTAL_ADDRESS, PP.TLNO
FROM USED_GOODS_BOARD AS GOODS JOIN PREPROCESSED AS PP
    ON GOODS.WRITER_ID = PP.USER_ID
GROUP BY PP.USER_ID
HAVING COUNT(GOODS.BOARD_ID) &gt;= 3
ORDER BY 1 DESC;</code></pre>
<br>
<br>
<br>

<h2 id="🚀-풀이기록">🚀 풀이기록</h2>
<h3 id="1-주소-표시">1. 주소 표시</h3>
<ul>
<li>주의! 전체주소 표시할 때 띄어쓰기 해주기 → 안하면 틀림</li>
</ul>
<pre><code class="language-sql">CONCAT(CITY,&#39; &#39;, STREET_ADDRESS1,&#39; &#39;, STREET_ADDRESS2) AS TOTAL_ADDRESS</code></pre>
<h3 id="2-전화번호-표시-숫자로만-이루어진-전화번호-컬럼에---을-삽입하는-방법">2. 전화번호 표시: 숫자로만 이루어진 전화번호 컬럼에  <code>-</code>을 삽입하는 방법</h3>
<ol>
<li><p><code>CONCAT()</code> 와 <code>SUBSTRING()</code>을 활용하는 방법</p>
<ul>
<li><code>SUBSTRING(phone_number, 시작위치, 길이)</code> 으로 부분 문자열을 추출하고, <code>CONCAT()</code> 으로 연결</li>
</ul>
<pre><code class="language-sql">CONCAT(SUBSTRING(TLNO,1, 3),&quot;-&quot;,
    SUBSTRING(TLNO,4, 4),&quot;-&quot;,
    SUBSTRING(TLNO,8, 4)) AS TLNO</code></pre>
</li>
<li><p><code>INSERT()</code>를 사용하여 특정 위치에 <code>-</code> 을 삽입하는 방법</p>
<ul>
<li><code>INSERT(TLNO, 위치, 제거할 문자 수, 삽입할 문자)</code></li>
</ul>
<pre><code class="language-sql">   INSERT(INSERT(TLNO, 4, 0, &#39;-&#39;), 9, 0, &#39;-&#39;) AS TLNO</code></pre>
<ol start="3">
<li><p><code>REGEXP_REPLACE()</code>를 활용(MySQL 8.0 이상)</p>
<ul>
<li><code>REGEXP_REPLACE(TLNO, 패턴, 대체 문자열)</code></li>
<li><code>(\\d{3})(\\d{4})(\\d{4})</code> : 숫자를 <code>3-3-4</code> 로 그룹화</li>
<li><code>$1-$2-$3</code> : 첫 번째 그룹, 두 번째 그룹, 세 번째 그룹을 <code>-</code> 로 연결</li>
</ul>
<pre><code class="language-sql">REGEXP_REPLACE(TLNO, &#39;(\\d{3})(\\d{4})(\\d{4})&#39;, &#39;$1-$2-$3&#39;) AS TLNO</code></pre>
</li>
</ol>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] 즐겨찾기가 가장 많은 식당 정보 출력하기]]></title>
            <link>https://velog.io/@mgr_baek/SQL-%EC%A6%90%EA%B2%A8%EC%B0%BE%EA%B8%B0%EA%B0%80-%EA%B0%80%EC%9E%A5-%EB%A7%8E%EC%9D%80-%EC%8B%9D%EB%8B%B9-%EC%A0%95%EB%B3%B4-%EC%B6%9C%EB%A0%A5%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@mgr_baek/SQL-%EC%A6%90%EA%B2%A8%EC%B0%BE%EA%B8%B0%EA%B0%80-%EA%B0%80%EC%9E%A5-%EB%A7%8E%EC%9D%80-%EC%8B%9D%EB%8B%B9-%EC%A0%95%EB%B3%B4-%EC%B6%9C%EB%A0%A5%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 10 Jun 2025 14:51:13 GMT</pubDate>
            <description><![CDATA[<h2 id="🔎-문제설명">🔎 문제설명</h2>
<ul>
<li>출처: <a href="https://school.programmers.co.kr/learn/courses/30/lessons/131123">프로그래머스</a></li>
<li>사용언어(RDBMS): SQL(MySQL)</li>
<li>문제:<blockquote>
<p><code>REST_INFO</code> 테이블에서 음식종류별로 즐겨찾기수가 가장 많은 식당의 음식 종류, ID, 식당 이름, 즐겨찾기수를 조회하는 SQL문을 작성해주세요. 이때 결과는 음식 종류를 기준으로 내림차순 정렬해주세요.</p>
</blockquote>
</li>
</ul>
<br>
<br>
<br>

<h2 id="✅-제출답안">✅ 제출답안</h2>
<pre><code class="language-sql"># 답안1 - JOIN을 사용
WITH MAX_FAVORITES AS(
    SELECT FOOD_TYPE, MAX(FAVORITES) AS FAVORITES
    FROM REST_INFO
    GROUP BY FOOD_TYPE
)
SELECT M.FOOD_TYPE, R.REST_ID, R.REST_NAME, M.FAVORITES
FROM MAX_FAVORITES AS M LEFT JOIN REST_INFO AS R
USING(FOOD_TYPE, FAVORITES)
ORDER BY FOOD_TYPE DESC;</code></pre>
<pre><code class="language-sql"># 답안2 - WHERE문을 사용
SELECT FOOD_TYPE, REST_ID, REST_NAME, FAVORITES
FROM REST_INFO
WHERE (FOOD_TYPE, FAVORITES) IN (SELECT FOOD_TYPE, MAX(FAVORITES)
                                 FROM REST_INFO
                                 GROUP BY FOOD_TYPE)
ORDER BY FOOD_TYPE DESC;</code></pre>
<br>
<br>
<br>

<h2 id="🚀-풀이기록">🚀 풀이기록</h2>
<p>처음에는 GROUP BY문으로 FOOD_TYPE을 기준으로 그룹화한다음, SELECT 문을 아래와 같이 작성했더니 틀렸다.</p>
<pre><code class="language-sql">SELECT FOOD_TYPE, REST_ID, REST_NAME, MAX(FAVORITES) AS FAVORITES</code></pre>
<p>생각해보면, FOOD_TYPE으로 그룹화했어도 REST_ID, REST_NAME에 대해 집계가 잡히지 않으니 오류없이 출력이 되었어도 사실은 틀렸다는 걸 의미했다. 문제를 읽었을 때는 쉬울줄 알았는데 10분 넘게 안 풀려서 시간재고 풀 당시에는 그냥 넘어갔었다. 앞으로 <code>GROUP BY</code>문을 사용할 때 이 부분을 주의해야 겠다.</p>
<p>추가적으로, 스터디원의 답안을 보며 WHERE문에서 반환한 서브쿼리의 여러쿼리의 쌍을 일치하는 행을 찾는게 가능하다는 사실도 알았다. 나중에 유용하게 쓰일 듯하다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] 부모의 형질을 모두 가지는 대장균 찾기]]></title>
            <link>https://velog.io/@mgr_baek/SQL-%EB%B6%80%EB%AA%A8%EC%9D%98-%ED%98%95%EC%A7%88%EC%9D%84-%EB%AA%A8%EB%91%90-%EA%B0%80%EC%A7%80%EB%8A%94-%EB%8C%80%EC%9E%A5%EA%B7%A0-%EC%B0%BE%EA%B8%B0</link>
            <guid>https://velog.io/@mgr_baek/SQL-%EB%B6%80%EB%AA%A8%EC%9D%98-%ED%98%95%EC%A7%88%EC%9D%84-%EB%AA%A8%EB%91%90-%EA%B0%80%EC%A7%80%EB%8A%94-%EB%8C%80%EC%9E%A5%EA%B7%A0-%EC%B0%BE%EA%B8%B0</guid>
            <pubDate>Tue, 10 Jun 2025 14:24:49 GMT</pubDate>
            <description><![CDATA[<h2 id="🔎-문제설명">🔎 문제설명</h2>
<ul>
<li>출처: <a href="https://school.programmers.co.kr/learn/courses/30/lessons/301647">프로그래머스</a></li>
<li>사용언어(RDBMS): SQL(MySQL)</li>
<li>문제:<blockquote>
<p>부모의 형질을 모두 보유한 대장균의 ID(ID), 대장균의 형질(GENOTYPE), 부모 대장균의 형질(PARENT_GENOTYPE)을 출력하는 SQL 문을 작성해주세요. 이때 결과는 ID에 대해 오름차순 정렬해주세요.</p>
</blockquote>
</li>
</ul>
<br>
<br>
<br>

<h2 id="✅-제출답안">✅ 제출답안</h2>
<pre><code class="language-sql"># 풀이1
SELECT D.ID, D.GENOTYPE, A.GENOTYPE AS PARENT_GENOTYPE
FROM ECOLI_DATA D LEFT JOIN ECOLI_DATA A ON D.PARENT_ID = A.ID
WHERE D.GENOTYPE ^ A.GENOTYPE = D.GENOTYPE - A.GENOTYPE
ORDER BY D.ID;

# 풀이2
SELECT D.ID, D.GENOTYPE, A.GENOTYPE AS PARENT_GENOTYPE
FROM ECOLI_DATA D LEFT JOIN ECOLI_DATA A ON D.PARENT_ID = A.ID
WHERE D.GENOTYPE &amp; A.GENOTYPE =  A.GENOTYPE
ORDER BY 1;</code></pre>
<br>
<br>
<br>

<h2 id="🚀-풀이기록">🚀 풀이기록</h2>
<p>_처음 이 문제를 접했을 때 부모의 형질을 담고 있는 자손을 어떻게 조건으로 걸어야 할지 1시간 넘게 고민했었다. 오늘 다시 풀었을 때 역시 이 부분이 가장 고민되었지만, 그래도 10분 내로 고민하고 해결할 수 있었다. _</p>
<hr>
<p>당시에 아래처럼 고민했었다.</p>
<blockquote>
<p><strong>부모의 형질을 모두 보유하고 있다는 의미</strong></p>
</blockquote>
<ol>
<li>부모와 같은 형질인 경우</li>
<li>부모의 형질을 가지면서 다른 형질도 가지고 있는 경우</li>
</ol>
<p>이걸 어떻게 쿼리문으로 나타낼지가 가장 큰 관건이다.</p>
<p>고민하다가 lv1에서 비슷한 문제가 나왔을 때 비트연산을 사용했던 것이 기억났다.</p>
<p>그렇다면 비트연산을 어떻게 적용해야할까?</p>
<ol>
<li><p><strong>부모와 같은 형질</strong>인 경우 ⇒ 비트연산없이 구현가능</p>
<ul>
<li>빼주면 0</li>
<li>나눠주면 1</li>
</ul>
</li>
<li><p><strong>부모의 형질을 가지면서 다른 형질</strong>도 가지고 있는 경우 ⇒ 이 부분이 어려움</p>
<ul>
<li><p>자손이 어떤 형질을 가지냐에 따라 빼기의 결과와 나눗셈의 결과가 달라짐</p>
<p>고민하다가</p>
</li>
<li><p>자손의 형질과 부모의 형질을 <code>XOR</code>연산을 하는 경우 자손이 추가적으로 갖는 형질만 남는다는 사실을 알게 됨(풀이1에 적용) 
⇒ <code>WHERE D.GENOTYPE ^ A.GENOTYPE = D.GENOTYPE - A.GENOTYPE</code></p>
</li>
<li><p>자손의 형질과 부모의 형질과 <code>AND</code>연산으로 비교할 경우 부모의 형질만 나타난다는 사실을 알게 됨(풀이2에 적용) 
⇒ <code>WHERE D.GENOTYPE &amp; A.GENOTYPE =  A.GENOTYPE</code></p>
</li>
</ul>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] 연도별 대장균 크기의 편차 구하기]]></title>
            <link>https://velog.io/@mgr_baek/SQL-%EC%97%B0%EB%8F%84%EB%B3%84-%EB%8C%80%EC%9E%A5%EA%B7%A0-%ED%81%AC%EA%B8%B0%EC%9D%98-%ED%8E%B8%EC%B0%A8-%EA%B5%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@mgr_baek/SQL-%EC%97%B0%EB%8F%84%EB%B3%84-%EB%8C%80%EC%9E%A5%EA%B7%A0-%ED%81%AC%EA%B8%B0%EC%9D%98-%ED%8E%B8%EC%B0%A8-%EA%B5%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 10 Jun 2025 13:37:51 GMT</pubDate>
            <description><![CDATA[<h2 id="🔎-문제설명">🔎 문제설명</h2>
<ul>
<li>출처: <a href="https://school.programmers.co.kr/learn/courses/30/lessons/299310">프로그래머스</a></li>
<li>사용언어(RDBMS): SQL(MySQL)</li>
<li>문제:<blockquote>
<p>분화된 연도(YEAR), 분화된 연도별 대장균 크기의 편차(YEAR_DEV), 대장균 개체의 ID(ID) 를 출력하는 SQL 문을 작성해주세요. 분화된 연도별 대장균 크기의 편차는 분화된 연도별 가장 큰 대장균의 크기 - 각 대장균의 크기로 구하며 결과는 연도에 대해 오름차순으로 정렬하고 같은 연도에 대해서는 대장균 크기의 편차에 대해 오름차순으로 정렬해주세요.</p>
</blockquote>
</li>
</ul>
<br>
<br>
<br>

<h2 id="✅-제출답안">✅ 제출답안</h2>
<pre><code class="language-sql"># with문을 사용한 답안
WITH MAX_SIZE_BY_YEAR AS (
SELECT YEAR(DIFFERENTIATION_DATE) AS YEAR, MAX(SIZE_OF_COLONY) AS MAX_SIZE
FROM ECOLI_DATA
GROUP BY YEAR(DIFFERENTIATION_DATE)
)
SELECT Y.YEAR, 
       Y.MAX_SIZE - E.SIZE_OF_COLONY AS YEAR_DEV, 
       ID
FROM ECOLI_DATA E LEFT JOIN MAX_SIZE_BY_YEAR Y 
    ON YEAR(DIFFERENTIATION_DATE) = Y.YEAR
ORDER BY 1, 2;</code></pre>
<pre><code class="language-sql"># with문을 사용하지 않은 답안
SELECT A.YEAR,
       A.MAX_SIZE - E.SIZE_OF_COLONY AS YEAR_DEV,
       E.ID
FROM ECOLI_DATA E JOIN (SELECT YEAR(DIFFERENTIATION_DATE) YEAR, 
                               MAX(SIZE_OF_COLONY) AS MAX_SIZE
                       FROM ECOLI_DATA
                       GROUP BY YEAR(DIFFERENTIATION_DATE)) A 
                       ON YEAR(E.DIFFERENTIATION_DATE) = A.YEAR
ORDER BY 1, 2;</code></pre>
<br>
<br>
<br>

<h2 id="🚀-풀이기록">🚀 풀이기록</h2>
<p><em>처음 이 문제를 접했을 때 with문을 사용해서 풀었고, 두 번째는 with문을 사용하지 않고 풀었다.</em></p>
<p>답안을 제출하면서 두번 모두 같은 부분에서 에러를 냈다.
GPT에게 물어본 결과, 위의 두 조건문의 차이는 <strong>테이블 별칭과 함수의 결합 방식 때문</strong>이라고 한다.</p>
<ol>
<li><p><strong>에러가 난 경우</strong></p>
<pre><code class="language-sql"> FROM ECOLI_DATA E LEFT JOIN MAX_SIZE_BY_YEAR Y 
     ON E.YEAR(DIFFERENTIATION_DATE) = Y.YEAR  </code></pre>
<p> E.YEAR(…)를 <code>테이블 별칭 + 함수 이름</code>형태를 함수 호출이 아닌 컬럼 참조로 착각할 수 있다고 한다. YEAR()는 함수인데다 해당 테이블에는 YEAR로 된 컬럼명이 없어서 에러가 발생했다고 한다.</p>
</li>
<li><p><strong>성공한 코드</strong></p>
<pre><code class="language-sql">
 FROM ECOLI_DATA E LEFT JOIN MAX_SIZE_BY_YEAR Y 
     ON YEAR(DIFFERENTIATION_DATE) = Y.YEAR
</code></pre>
<p> 테이블 별칭을 제거하고 YEAR(컬럼명)만 사용한 경우, YEAR(…)함수 안에 직접 컬럼 이름을 넣었고, <code>DIFFERENTIATION_DATE</code> 컬럼은 ECOLI_DATA 테이블에만 존재하므로 에러없이 실행되었다고 한다.</p>
</li>
<li><p><strong>에러 없이 테이블을 명시해서 사용하는 경우</strong> </p>
<pre><code class="language-sql"> FROM ECOLI_DATA E LEFT JOIN MAX_SIZE_BY_YEAR Y 
     ON YEAR(E.DIFFERENTIATION_DATE) = Y.YEAR</code></pre>
<p> <code>YEAR()</code>함수를 그대로 쓰되, 함수안에서만 테이블 별칭을 붙이면 정확하게 해석된다고 한다.</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] 조건에 맞는 개발자 찾기]]></title>
            <link>https://velog.io/@mgr_baek/SQL-%EC%A1%B0%EA%B1%B4%EC%97%90-%EB%A7%9E%EB%8A%94-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EC%B0%BE%EA%B8%B0</link>
            <guid>https://velog.io/@mgr_baek/SQL-%EC%A1%B0%EA%B1%B4%EC%97%90-%EB%A7%9E%EB%8A%94-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EC%B0%BE%EA%B8%B0</guid>
            <pubDate>Tue, 10 Jun 2025 13:13:22 GMT</pubDate>
            <description><![CDATA[<h2 id="🔎-문제설명">🔎 문제설명</h2>
<ul>
<li>출처: <a href="https://school.programmers.co.kr/learn/courses/30/lessons/276034">프로그래머스</a></li>
<li>사용언어(RDBMS): SQL(MySQL)</li>
<li>문제:<blockquote>
<p>DEVELOPERS 테이블에서 Python이나 C# 스킬을 가진 개발자의 정보를 조회하려 합니다. 조건에 맞는 개발자의 ID, 이메일, 이름, 성을 조회하는 SQL 문을 작성해 주세요. 결과는 ID를 기준으로 오름차순 정렬해 주세요.</p>
</blockquote>
</li>
</ul>
<br>
<br>
<br>

<h2 id="✅-제출답안">✅ 제출답안</h2>
<pre><code class="language-sql"># 풀이1 - 조인 후 조건을 걸어줌
SELECT DISTINCT(D.ID), D.EMAIL, D.FIRST_NAME, D.LAST_NAME
FROM DEVELOPERS AS D JOIN SKILLCODES AS S 
    ON D.SKILL_CODE &amp; S.CODE
WHERE S.NAME IN (&#39;PYTHON&#39;, &#39;C#&#39;)
ORDER BY D.ID;

# 풀이2 - where문에서 조건을 걸어줌
SELECT ID, EMAIL, FIRST_NAME, LAST_NAME
FROM DEVELOPERS
WHERE SKILL_CODE &amp; (SELECT SUM(CODE)
                         FROM SKILLCODES
                         WHERE NAME IN (&#39;Python&#39;, &#39;C#&#39;))
ORDER BY ID;

# 풀이3 - 조건을 걸어준 쿼리를 조인함
SELECT DISTINCT(D.ID), D.EMAIL, D.FIRST_NAME, D.LAST_NAME
FROM DEVELOPERS AS D JOIN (SELECT CODE
                           FROM SKILLCODES
                           WHERE NAME IN (&#39;PYTHON&#39;,&#39;C#&#39;)) AS S
                           ON D.SKILL_CODE &amp; S.CODE 
ORDER BY D.ID</code></pre>
<br>
<br>
<br>

<h2 id="🚀-풀이기록">🚀 풀이기록</h2>
<p>처음 이 문제를 접했을 때, <code>code</code>컬럼을 이진수로 변환하려는 시도를 했었다. 이후 <code>&amp;</code>연산을 사용한 비트연산으로 문제를 풀어야 된다는 사실을 알게 되었고, 위와 같이 3가지 풀이법을 사용해 해결했다. 
여기서 주의할 점은 <strong>풀이2</strong>에서는 Python과 C#에 해당하는 코드를 이미 합쳐주었기 때문에 하나의 값으로 결과가 나온다. 하지만 <strong>풀이1</strong>과 <strong>풀이3</strong>은 <code>WHERE</code>문에서 Python과 C#에 해당하는 튜플이 두 줄로 나온다. 따라서 <code>JOIN</code> 후에 같은 행이 중복으로 나타나는 걸 방지하기 위해(개발자가 Python과 C#스킬을 모두 가지는 경우) <code>SELECT</code>문에서 <code>DISTINCT</code>를 사용해주어야 한다.</p>
<p>추가적으로, 문제를 풀면서 JOIN의 ON절에 꼭 <code>=</code> 연산자뿐만 아니라 다양한 비교연산자(<code>&gt;</code>,<code>&lt;</code>,<code>&lt;=</code>,<code>&gt;=</code>), BETWEEN, LIKE, IN등 여러 연산자가 사용가능하다는 사실을 알게 되었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] 업그레이드 된 아이템 구하기]]></title>
            <link>https://velog.io/@mgr_baek/SQL-%EC%97%85%EA%B7%B8%EB%A0%88%EC%9D%B4%EB%93%9C-%EB%90%9C-%EC%95%84%EC%9D%B4%ED%85%9C-%EA%B5%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@mgr_baek/SQL-%EC%97%85%EA%B7%B8%EB%A0%88%EC%9D%B4%EB%93%9C-%EB%90%9C-%EC%95%84%EC%9D%B4%ED%85%9C-%EA%B5%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 10 Jun 2025 12:35:29 GMT</pubDate>
            <description><![CDATA[<h2 id="🔎-문제설명">🔎 문제설명</h2>
<ul>
<li>출처: <a href="https://school.programmers.co.kr/learn/courses/30/lessons/273711">프로그래머스</a></li>
<li>사용언어(RDBMS): SQL(MySQL)</li>
<li>문제:<blockquote>
<p>아이템의 희귀도가 <code>RARE</code>인 아이템들의 모든 다음 업그레이드 아이템의 아이템 ID(ITEM_ID), 아이템 명(ITEM_NAME), 아이템의 희귀도(RARITY)를 출력하는 SQL 문을 작성해 주세요. 이때 결과는 아이템 ID를 기준으로 내림차순 정렬주세요.</p>
</blockquote>
</li>
</ul>
<br>
<br>
<br>

<h2 id="✅-제출답안">✅ 제출답안</h2>
<pre><code class="language-sql"># WHERE문을 사용해서 푼 경우
SELECT ITEM_ID, ITEM_NAME, RARITY
FROM ITEM_INFO
WHERE ITEM_ID IN (SELECT IT.ITEM_ID
                  FROM ITEM_INFO AS II RIGHT JOIN ITEM_TREE AS IT
                       ON II.ITEM_ID = IT.PARENT_ITEM_ID
                  WHERE II.RARITY = &#39;RARE&#39;)
ORDER BY ITEM_ID DESC;</code></pre>
<pre><code class="language-sql"># JOIN을 사용해서 푼 경우
SELECT II.ITEM_ID, ITEM_NAME, RARITY
FROM ITEM_INFO II JOIN (SELECT T.ITEM_ID
                        FROM ITEM_INFO I JOIN ITEM_TREE T ON I.ITEM_ID = T.PARENT_ITEM_ID 
                        WHERE I.RARITY = &#39;RARE&#39;) UI ON II.ITEM_ID = UI.ITEM_ID
ORDER BY 1 DESC;</code></pre>
<br>
<br>
<br>

<h2 id="🚀-풀이기록">🚀 풀이기록</h2>
<p>처음에 풀었을 때가 where문을 사용해서 풀었고, 두번째 풀이에 도전했을 때가 join을 사용해서 풀었다. where문을 사용해서 푼 풀이가 join을 한 번만 사용해서 푼 풀이여서 더 좋은 풀이이지 않을까라는 생각이 든다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] 노선별 평균 역 사이 거리 조회하기]]></title>
            <link>https://velog.io/@mgr_baek/SQL-%EB%85%B8%EC%84%A0%EB%B3%84-%ED%8F%89%EA%B7%A0-%EC%97%AD-%EC%82%AC%EC%9D%B4-%EA%B1%B0%EB%A6%AC-%EC%A1%B0%ED%9A%8C%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@mgr_baek/SQL-%EB%85%B8%EC%84%A0%EB%B3%84-%ED%8F%89%EA%B7%A0-%EC%97%AD-%EC%82%AC%EC%9D%B4-%EA%B1%B0%EB%A6%AC-%EC%A1%B0%ED%9A%8C%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 10 Jun 2025 12:02:49 GMT</pubDate>
            <description><![CDATA[<h2 id="🔎-문제설명">🔎 문제설명</h2>
<ul>
<li>출처: <a href="https://school.programmers.co.kr/learn/courses/30/lessons/284531">프로그래머스</a></li>
<li>사용언어(RDBMS): SQL(MySQL)</li>
<li>문제:<blockquote>
<p><code>SUBWAY_DISTANCE</code> 테이블에서 노선별로 노선, 총 누계 거리, 평균 역 사이 거리를 노선별로 조회하는 SQL문을 작성해주세요.
총 누계거리는 테이블 내 존재하는 역들의 역 사이 거리의 총 합을 뜻합니다. 총 누계 거리와 평균 역 사이 거리의 컬럼명은 각각 <code>TOTAL_DISTANCE</code>, <code>AVERAGE_DISTANCE</code>로 해주시고, 총 누계거리는 소수 둘째자리에서, 평균 역 사이 거리는 소수 셋째 자리에서 반올림 한 뒤 단위(km)를 함께 출력해주세요.
결과는 총 누계 거리를 기준으로 내림차순 정렬해주세요.</p>
</blockquote>
</li>
</ul>
<br>
<br>
<br>

<h2 id="✅-제출답안">✅ 제출답안</h2>
<pre><code class="language-sql">SELECT ROUTE,
        CONCAT(ROUND(SUM(D_BETWEEN_DIST), 1), &#39;km&#39;) AS TOTAL_DISTANCE,
        CONCAT(ROUND(AVG(D_BETWEEN_DIST), 2), &#39;km&#39;) AS AVERAGE_DISTANCE
 FROM SUBWAY_DISTANCE
 GROUP BY ROUTE
 ORDER BY ROUND(SUM(D_BETWEEN_DIST), 1) DESC;</code></pre>
<br>
<br>
<br>

<h2 id="🚀-풀이기록">🚀 풀이기록</h2>
<p>처음에 ORDER BY문에서 문자열로 바뀐 <code>TOTAL_DISTANCE</code>를 그대로 써서 틀렸다. ORDER BY문을 소수 둘째자리에서 반올림한 총 누계거리로 바꾼뒤 채점해도 틀렸다고 나왔는데, 알고봤더니 SELECT문이 한 칸 들여쓰기 되어있던 게 문제였다… 사소한거지만 앞으로 주의해야겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] 자동차 평균 대여 기간 구하기]]></title>
            <link>https://velog.io/@mgr_baek/SQL-%EC%9E%90%EB%8F%99%EC%B0%A8-%ED%8F%89%EA%B7%A0-%EB%8C%80%EC%97%AC-%EA%B8%B0%EA%B0%84-%EA%B5%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@mgr_baek/SQL-%EC%9E%90%EB%8F%99%EC%B0%A8-%ED%8F%89%EA%B7%A0-%EB%8C%80%EC%97%AC-%EA%B8%B0%EA%B0%84-%EA%B5%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 10 Jun 2025 11:43:53 GMT</pubDate>
            <description><![CDATA[<h2 id="🔎-문제설명">🔎 문제설명</h2>
<ul>
<li>출처: <a href="https://school.programmers.co.kr/learn/courses/30/lessons/157342">프로그래머스</a></li>
<li>사용언어(RDBMS): SQL(MySQL)</li>
<li>문제:<blockquote>
<p><code>CAR_RENTAL_COMPANY_RENTAL_HISTORY</code> 테이블에서 평균 대여 기간이 7일 이상인 자동차들의 자동차 ID와 평균 대여 기간(컬럼명: AVERAGE_DURATION) 리스트를 출력하는 SQL문을 작성해주세요. 평균 대여 기간은 소수점 두번째 자리에서 반올림하고, 결과는 평균 대여 기간을 기준으로 내림차순 정렬해주시고, 평균 대여 기간이 같으면 자동차 ID를 기준으로 내림차순 정렬해주세요.</p>
</blockquote>
</li>
</ul>
<br>
<br>
<br>

<h2 id="✅-제출답안">✅ 제출답안</h2>
<pre><code class="language-sql"># 평균 대여 기간이 7일 이상인 자동차들의 자동차 ID와 평균 대여 기간(AVERAGE_DURATION)리스트를 출력
# 평균 대여 기간은 소수점 두번째 자리에서 반올림
# 평균 대여 기간을 기준으로 내림차순, 자동차 ID를 기준으로 내림차순

SELECT CAR_ID, 
       ROUND(AVG(DATEDIFF(END_DATE, START_DATE) + 1),  1) AS AVERAGE_DURATION
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
GROUP BY CAR_ID
HAVING ROUND(AVG(DATEDIFF(END_DATE, START_DATE) + 1),  1)  &gt;= 7
ORDER BY AVERAGE_DURATION DESC, CAR_ID DESC;</code></pre>
<br>
<br>
<br>

<h2 id="🚀-풀이기록">🚀 풀이기록</h2>
<p>처음에는 아래와 같이 작성해서 제출했는데 틀렸다.</p>
<pre><code class="language-sql">SELECT CAR_ID, 
       ROUND(AVG(END_DATE - START_DATE + 1), 2) AS AVERAGE_DURATION
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY 
GROUP BY CAR_ID
HAVING AVG(END_DATE - START_DATE + 1) &gt;= 7
ORDER BY AVERAGE_DURATION DESC, CAR_ID DESC;</code></pre>
<p><code>DATEDIFF()</code>함수를 쓰지 않고, 바로 <code>END_DATE - START_DATE + 1</code>로 계산했더니, 숫자가 크게 나왔다. <code>DATEDIFF()</code>함수를 쓰지 않으면 <code>END_DATE</code>와 <code>START_DATE</code>에 입력된 날짜를 숫자로 변환하여 계산되었기 때문이었다. 예를 들어, 2024-10-10과 2024-11-10 동안 대여했다고 하면 20241110-20241010 = 100이라는 결과가 나왔다. 풀이 게시판에서 다른 분들도 이렇게 계산한 거 같았다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] 조건에 맞는 사원 정보 조회하기]]></title>
            <link>https://velog.io/@mgr_baek/SQL-%EC%A1%B0%EA%B1%B4%EC%97%90-%EB%A7%9E%EB%8A%94-%EC%82%AC%EC%9B%90-%EC%A0%95%EB%B3%B4-%EC%A1%B0%ED%9A%8C%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@mgr_baek/SQL-%EC%A1%B0%EA%B1%B4%EC%97%90-%EB%A7%9E%EB%8A%94-%EC%82%AC%EC%9B%90-%EC%A0%95%EB%B3%B4-%EC%A1%B0%ED%9A%8C%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 10 Jun 2025 11:22:06 GMT</pubDate>
            <description><![CDATA[<h2 id="🔎-문제설명">🔎 문제설명</h2>
<ul>
<li>출처: <a href="https://school.programmers.co.kr/learn/courses/30/lessons/284527">프로그래머스</a></li>
<li>사용언어(RDBMS): SQL(MySQL)</li>
<li>문제:<blockquote>
<p><code>HR_DEPARTMENT</code>, <code>HR_EMPLOYEES</code>, <code>HR_GRADE</code> 테이블에서 2022년도 한해 평가 점수가 가장 높은 사원 정보를 조회하려 합니다. 2022년도 평가 점수가 가장 높은 사원들의 점수, 사번, 성명, 직책, 이메일을 조회하는 SQL문을 작성해주세요. 2022년도의 평가 점수는 상,하반기 점수의 합을 의미하고, 평가 점수를 나타내는 컬럼의 이름은 SCORE로 해주세요.</p>
</blockquote>
</li>
</ul>
<br>
<br>
<br>

<h2 id="✅-제출답안">✅ 제출답안</h2>
<pre><code class="language-sql"># 풀이1
SELECT SUM(HG.SCORE) AS SCORE, 
       HE.EMP_NO, 
       HE.EMP_NAME, 
       HE.POSITION, 
       HE.EMAIL 
FROM HR_GRADE AS HG JOIN HR_EMPLOYEES AS HE 
    ON HG.EMP_NO = HE.EMP_NO
WHERE HG.YEAR = 2022
GROUP BY EMP_NO
ORDER BY SCORE DESC
LIMIT 1;
</code></pre>
<br>
<br>
<br>

<h2 id="🚀-풀이기록">🚀 풀이기록</h2>
<p>처음 문제를 풀었을 때 풀이1방법으로 풀었다. 이 풀이 단점은 평가점수가 가장 높은 사람의 수가 다수일경우에도 한 명만 출력이 된다는 단점이 있었다. 프로그래머스에서 다른 분들이 작성한 답안을 참고하며, <code>with</code>문을 사용하여 코드를 작성하는게 가독성도 더 좋고 효율적인 거 같아보였다.</p>
<pre><code class="language-sql"># 다른 분들의 답변을 참고해 다시 작성한 답안
## 직원별 2022년의 평가점수를 나타내는 쿼리작성
WITH SCORE_2022 AS (
    SELECT EMP_NO, SUM(SCORE) AS TOTAL_SCORE
    FROM HR_GRADE
    WHERE YEAR = &#39;2022&#39;
    GROUP BY EMP_NO
)

SELECT TOTAL_SCORE AS SCORE,
       HE.EMP_NO,
       HE.EMP_NAME,
       HE.POSITION,
       HE.EMAIL
FROM HR_EMPLOYEES HE INNER JOIN SCORE_2022 USING(EMP_NO)
WHERE TOTAL_SCORE = (SELECT MAX(TOTAL_SCORE)
                     FROM SCORE_2022)  # 최고점의 평가점수를 받은 쿼리만 추출
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] 가격대 별 상품 개수 구하기]]></title>
            <link>https://velog.io/@mgr_baek/SQL-%EA%B0%80%EA%B2%A9%EB%8C%80-%EB%B3%84-%EC%83%81%ED%92%88-%EA%B0%9C%EC%88%98-%EA%B5%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@mgr_baek/SQL-%EA%B0%80%EA%B2%A9%EB%8C%80-%EB%B3%84-%EC%83%81%ED%92%88-%EA%B0%9C%EC%88%98-%EA%B5%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 11 May 2025 14:28:45 GMT</pubDate>
            <description><![CDATA[<h2 id="🔎-문제설명">🔎 문제설명</h2>
<ul>
<li>출처: <a href="https://school.programmers.co.kr/learn/courses/30/lessons/131530">프로그래머스</a></li>
<li>사용언어(RDBMS): SQL(MySQL)</li>
<li>문제:<blockquote>
<p><code>PRODUCT</code> 테이블에서 만원 단위의 가격대 별로 상품 개수를 출력하는 SQL 문을 작성해주세요. 이때 컬럼명은 각각 컬럼명은 PRICE_GROUP, PRODUCTS로 지정해주시고 가격대 정보는 각 구간의 최소금액(10,000원 이상 ~ 20,000 미만인 구간인 경우 10,000)으로 표시해주세요. 결과는 가격대를 기준으로 오름차순 정렬해주세요.</p>
</blockquote>
</li>
</ul>
<br>
<br>
<br>

<h2 id="✅-제출답안">✅ 제출답안</h2>
<pre><code class="language-sql"># 만원 단위의 가격대 별로 상품 개수를 출력
# 가격대 정보는 각 구간의 최소금액
# 가격대를 기준으로 오름차순 정렬
SELECT IF(PRICE &lt; 10000, 0, CONCAT(SUBSTR(PRICE, 1, 1), &#39;0000&#39;)) AS PRICE_GROUP, COUNT(PRODUCT_ID) AS PRODUCTS
FROM PRODUCT 
GROUP BY PRICE_GROUP
ORDER BY PRICE_GROUP;</code></pre>
<br>
<br>
<br>

<h2 id="🚀-풀이기록">🚀 풀이기록</h2>
<p> 문제를 푼지 시간이 지나고 다시 보니, 내가 생각해도 저렇게 푼게 내 자신이 신기하다(역시 과거의 나는 타인이었어...) 그 때는 시간제한을 두고 풀었으니 어떻게든 푸는데 초점을 두다보니 그런 거 같다.</p>
<ol>
<li><p><code>PRICE_GROUP</code>: 문제를 풀 당시 물건의 최대가격이 80000원이라는 사실을 확인하고, IF문을 만들 때 만 원 미만의 상품에 대해서는 0으로 처리하고, 만원 이상이 상품에 대해서는 가장 앞자리에 있는 문자를 추출해 0을 4개 붙여주는 방식을 취했다. 여기서 CONCAT과 SUBSTR을 사용했는데, 당시 기록을 보니 두 함수가 기억이 나지 않아 지난 문제들을 참고해서 풀었다. 
다른 분들의 답과 비교해보니 그 분들의 답안이 더 범용적인 것 같아 적어본다. 다음에 다른 문제를 풀 때 참고하면 좋을 거 같다.</p>
<pre><code class="language-sql"># PRICE를 끝에서 4번째 자리까지 절삭
SELECT CASE WHEN PRICE &lt; 10000 THEN 0
         ELSE TRUNCATE (PRICE, -4) END AS PRICE_GROUP

# PRICE를 10000으로 나눈 뒤, FLOOR()을 사용하여 결과값보다 크지 않는 정수 반환 
SELECT FLOOR(PRICE/10000)*10000 AS PRICE_GROUP
# 같은 방법: SELECT FLOOR(PRICE*0.0001)*10000 AS PRICE_GROUP</code></pre>
<br>

<ol start="2">
<li>SELECT문에 있는 ALIAS를 GROUP BY문에서도 사용할 수 있다는 사실을 알게되었다.  이에 대해 어떻게 GROUP BY문에서도 SELECT에 있는 ALIAS를 사용할 수 있는지를 GPT에게 물어봤더니 다음과 같이 정리해주었다.<h3 id="✅-📌-정리-alias-사용-가능-여부">✅ <strong>📌 정리: <code>ALIAS</code> 사용 가능 여부</strong></h3>
</li>
</ol>
<table>
<thead>
<tr>
<th>절</th>
<th><code>ALIAS</code> 사용 가능 여부</th>
<th>이유</th>
</tr>
</thead>
<tbody><tr>
<td><code>WHERE</code></td>
<td>❌ 불가능</td>
<td><code>WHERE</code>은 <code>SELECT</code>보다 먼저 실행되므로, <code>ALIAS</code>를 참조할 수 없음.</td>
</tr>
<tr>
<td><code>GROUP BY</code></td>
<td>⭕ 일부 DBMS에서는 가능</td>
<td>MySQL은 최적화를 통해 <code>ALIAS</code> 사용을 허용. 하지만 표준 SQL은 불가.</td>
</tr>
<tr>
<td><code>HAVING</code></td>
<td>⭕ 일부 DBMS에서는 가능</td>
<td>MySQL에서는 <code>ALIAS</code>를 허용하지만, 표준 SQL에서는 원래 컬럼명을 사용해야 함.</td>
</tr>
<tr>
<td><code>ORDER BY</code></td>
<td>⭕ 가능</td>
<td><code>ORDER BY</code>는 <code>SELECT</code> 이후에 실행되므로 <code>ALIAS</code>를 사용할 수 있음.</td>
</tr>
</tbody></table>
</li>
</ol>
<p>➡ <strong>결론:</strong> <code>ORDER BY</code>에서는 100% 가능, <code>GROUP BY</code>와 <code>HAVING</code>은 MySQL에서는 가능하지만 표준 SQL에서는 불가능할 수도 있음.</p>
<p>➡ <strong><code>WHERE</code>에서는 절대 사용할 수 없음!</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] 조건에 맞는 도서와 리스트 출력하기]]></title>
            <link>https://velog.io/@mgr_baek/SQL-%EC%A1%B0%EA%B1%B4%EC%97%90-%EB%A7%9E%EB%8A%94-%EB%8F%84%EC%84%9C%EC%99%80-%EB%A6%AC%EC%8A%A4%ED%8A%B8-%EC%B6%9C%EB%A0%A5%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@mgr_baek/SQL-%EC%A1%B0%EA%B1%B4%EC%97%90-%EB%A7%9E%EB%8A%94-%EB%8F%84%EC%84%9C%EC%99%80-%EB%A6%AC%EC%8A%A4%ED%8A%B8-%EC%B6%9C%EB%A0%A5%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 11 May 2025 14:06:15 GMT</pubDate>
            <description><![CDATA[<h3 id="🔎-문제설명">🔎 문제설명</h3>
<ul>
<li>출처: <a href="https://school.programmers.co.kr/learn/courses/30/lessons/144854">프로그래머스</a></li>
<li>사용언어(RDBMS): SQL(MySQL)</li>
<li>문제:<blockquote>
<p><code>경제</code> 카테고리에 속하는 도서들의 도서 ID(BOOK_ID), 저자명(AUTHOR_NAME), 출판일(PUBLISHED_DATE) 리스트를 출력하는 SQL문을 작성해주세요.
결과는 출판일을 기준으로 오름차순 정렬해주세요.</p>
</blockquote>
</li>
</ul>
<br>
<br>
<br>

<h3 id="✅-제출답안">✅ 제출답안</h3>
<pre><code class="language-sql"># &#39;경제&#39; 카테고리에 속하는 도서들의 도서 ID(BOOK_ID), 저자명(AUTHOR_NAME), 출판일(PUBLISHED_DATE) 리스트를 출력
# 출판일을 기준으로 오름차순 정렬
SELECT B.BOOK_ID, A.AUTHOR_NAME, DATE_FORMAT(B.PUBLISHED_DATE, &quot;%Y-%m-%d&quot;) AS PUBLISHED_DATE
FROM BOOK AS B JOIN AUTHOR AS A ON B.AUTHOR_ID = A.AUTHOR_ID
WHERE B.CATEGORY = &#39;경제&#39;
ORDER BY 3;</code></pre>
<br>
<br>
<br>

<h3 id="🚀-풀이기록">🚀 풀이기록</h3>
<p>문제를 푼 뒤, 다르게 작성한 답안도 찾아보았다. join에서 조건을 달아준 답안을 확인할 수 있었다(출처: <a href="https://dataengineerstudy.tistory.com/208">조건에 맞는 도서와 저자 리스트 출력하기(JOIN 에서 WHERE 와 ON 의 차이)</a>). 링크에 where와 on의 차이를 나와있는데, 결론은 join을 할 때 on절에서 조건을 걸어 필터링을 해주는게 쿼리 최적화에 좋다고 한다. 자세한 내용은 링크를 참고하자!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] 입양 시각 구하기(1)]]></title>
            <link>https://velog.io/@mgr_baek/SQL-%EC%9E%85%EC%96%91-%EC%8B%9C%EA%B0%81-%EA%B5%AC%ED%95%98%EA%B8%B01</link>
            <guid>https://velog.io/@mgr_baek/SQL-%EC%9E%85%EC%96%91-%EC%8B%9C%EA%B0%81-%EA%B5%AC%ED%95%98%EA%B8%B01</guid>
            <pubDate>Sun, 11 May 2025 13:55:09 GMT</pubDate>
            <description><![CDATA[<h3 id="🔎-문제설명">🔎 문제설명</h3>
<ul>
<li>출처: <a href="https://school.programmers.co.kr/learn/courses/30/lessons/59412">프로그래머스</a></li>
<li>사용언어(RDBMS): SQL(MySQL)</li>
<li>문제:<blockquote>
<p>보호소에서는 몇 시에 입양이 가장 활발하게 일어나는지 알아보려 합니다. 09:00부터 19:59까지, 각 시간대별로 입양이 몇 건이나 발생했는지 조회하는 SQL문을 작성해주세요. 이때 결과는 시간대 순으로 정렬해야 합니다.</p>
</blockquote>
</li>
</ul>
<br>
<br>
<br>

<h3 id="✅-제출답안">✅ 제출답안</h3>
<pre><code class="language-sql"># 09:00부터 19:59까지, 각 시간대별로 입양이 몇 건이나 발생했는지 조회
# 결과는 시간대 순으로 정렬
SELECT HOUR(DATETIME) AS HOUR, COUNT(ANIMAL_ID) AS COUNT
FROM ANIMAL_OUTS
GROUP BY HOUR(DATETIME)
HAVING HOUR &gt;= 9 AND HOUR &lt;=19
ORDER BY 1;</code></pre>
<br>
<br>
<br>

<h3 id="🚀-풀이기록">🚀 풀이기록</h3>
<p>다른 사람들의 답을 보며, WHERE문을 사용하여 간결하게 답을 작성한 게 있어 가져와보았다.</p>
<pre><code class="language-sql">WHERE DATE_FORMAT(datetime, &#39;%H&#39;) BETWEEN 09 AND 19</code></pre>
<p>이 문제를 푼지 3달이 넘어가는 시점에서 다시 답을 보니, 내가 작성한 답도 가독성면에서 괜찮아보였다. 처음에 문제풀고 나서 다른 사람들의 답이 더 좋아보였는데... 그게 자격지심 아니었나 생각해본다. 코드의 길이, 효율성도 중요하지만 다른 사람들과 함께 공유하기 좋은 코드가 무엇인지 고민하게 된다.</p>
]]></description>
        </item>
    </channel>
</rss>