10일차

Suhyeon Lee·2024년 10월 15일
0
post-thumbnail

CodeKata

SQL

55. 조건에 맞는 사용자 정보 조회하기

  • 처음 작성한 쿼리 → 오답이라고 나옴
SELECT
  writer_id
  , nickname
  , `전체주소`
  , `전화번호`
FROM (
  SELECT
    b.writer_id
    , u.nickname
    , CONCAT(city, ' ', street_address1, street_address2) AS "전체주소"
    , CONCAT(SUBSTR(tlno, 1, 3), '-', SUBSTR(tlno, 4, 4), '-', SUBSTR(tlno, 8, 4)) AS "전화번호"
    , COUNT(b.writer_id) AS cnt
  FROM
    used_goods_board AS b
    JOIN used_goods_user AS u
    ON b.writer_id = u.user_id
  GROUP BY
    1, 2, 3, 4
  ) AS ug
WHERE
  cnt >= 3
ORDER BY
  writer_id DESC
;

→ user_id를 조회해야 하는데 writer_id를 써서 그런가? 하고 다시 고쳤는데 여전히 오답
→ 알고보니 CONCAT(city, ' ', street_address1, street_address2) 문제였음

  • 실행 결과 화면에서 city컬럼과 street_address1컬럼 사이만 띄어쓰기가 안 되어 있는 것처럼 보이길래 공란을 하나만 넣었는데 알고 보니 컬럼과 컬럼 사이에 무조건 넣어야 했음 (잘 보면 띄어쓰기가 없다는 게 보임: '수내로 1'과 '001-004', '내정로165번길 35'와 '104-1202' 사이에 띄어쓰기 필요함)

  • 정답으로 처리된 쿼리

SELECT
  user_id
  , nickname
  , `전체주소`
  , `전화번호`
FROM (
  SELECT
    u.user_id
    , u.nickname
    , CONCAT(city, ' ', street_address1, ' ', street_address2) AS "전체주소"
    , CONCAT(SUBSTR(tlno, 1, 3), '-', SUBSTR(tlno, 4, 4), '-', SUBSTR(tlno, 8, 4)) AS "전화번호"
    , COUNT(b.writer_id) AS cnt
  FROM
    used_goods_board AS b
    JOIN used_goods_user AS u
    ON b.writer_id = u.user_id
  GROUP BY
    1, 2, 3, 4
  ) AS ug
WHERE
  cnt >= 3
ORDER BY
  user_id DESC
;
  • 다른 방식으로도 풀어보았음
SELECT
  u.user_id
  , u.nickname
  , CONCAT(city, ' ', street_address1, ' ', street_address2) AS "전체주소"
  , CONCAT(SUBSTR(tlno, 1, 3), '-', SUBSTR(tlno, 4, 4), '-', SUBSTR(tlno, 8, 4)) AS "전화번호"
FROM
  used_goods_board AS b
  JOIN used_goods_user AS u
  ON b.writer_id = u.user_id
GROUP BY
  u.user_id
HAVING
  COUNT(*) >= 3
ORDER BY
  user_id DESC
;
SELECT
  user_id
  , nickname
  , CONCAT_WS(' ', city, street_address1, street_address2) AS "전체주소"
  , CONCAT_WS('-', SUBSTR(tlno, 1, 3), SUBSTR(tlno, 4, 4), SUBSTR(tlno, 8, 4)) AS "전화번호"
FROM
  used_goods_user
WHERE user_id IN (
  SELECT
    writer_id
  FROM
    used_goods_board
  GROUP BY
    writer_id
  HAVING
    COUNT(*) >= 3
  )
ORDER BY
  user_id DESC
;

CONCAT은 컬럼(필드) 문자열들을 결합해 하나의 열로 표현할 때 사용
CONCAT_WS는 문자열을 결합할 때마다 지정된 구문자를 사이에 넣어줌
(WS는 With Separator의 약자)
구분자를 제공하지 않으면 자동으로 구분자가 없는 CONCAT()와 동일하게 작동하며 결합할 값이 NULL이면 해당 값은 무시됨
CONCAT은 연산자 ||(Double Vertical bars, 더블 버티컬 바)로도 사용할 수 있음
단, MySCL에서는 ||가 'Logical OR'라 사용 불가

참고할 만한 다른 풀이

  1. ※ 내가 추가로 푼 방법 중 2번째 방법은 WHERE절에서 각 ROW마다 매번 서브쿼리가 실행되어 성능상 좋지 않아 CTE를 통해 1번만 실행되도록 하는 게 좋다고 함
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
  user_id DESC
;
  • INSERT() 함수
    • 문자열의 특정 위치에 새로운 문자열을 삽입하는 함수
    • 기존 문자열의 일부분을 대체하거나 새로운 문자열 삽입 가능
INSERT(original_string, position, length, new_string)

-- 예시
SELECT
  INSERT('01012345678', 4, 0, '-') # 010-12345678
  • original_string: 수정할 원본 문자열
  • position: 새로운 문자열을 삽입할 위치
    • 맨 앞 1부터 시작
      [1]0[2]1[3]0[4]12345678
  • length: 대체할 문자열의 길이
    • 0으로 설정하면 기존 문자열을 대체하지 않고 삽입만 함
  • new_string: 삽입할 새로운 문자열

🎯 집계함수를 이용해 조건 비교를 하고 싶으면 GROUP BY & HAVING 사용하거나 서브쿼리 사용해야 함
WHERE절에 단독으로 집계함수 쓸 수 없음(당연함. 집계 연산은 WHERE절 이후 진행임.)

  1. 주소 체계 특징 상 street_address2는 NULL일 수도 있다는 의견
    → e.g. 서울 종로구 세종대로 209
    이 경우 COALESCE 함수를 활용하면 된다고 함: CONCAT_WS(' ', CITY, STREET_ADDRESS1, COALESCE(STREET_ADDRESS2, ''))
  • COALESCE(): 인수로 전달된 값 중에서 가장 먼저 등장하는 NULL이 아닌 값 선택
  1. 전화번호에 정규표현식 써도 됨
    REGEXP_REPLACE(TLNO, '(.{3})(.{4})(.{4})', '$1-$2-$3') 전화번호

Python

11. 짝수와 홀수

  • 작성한 코드
def solution(num):
    if num%2 > 0:
        return "Odd"
    else:
        return "Even"

참고할 만한 풀이

def evenOrOdd(num):
    if num%2:
        return "Odd"
    return "Even"
  • and 연산자는 결과값이 둘 다 참이여야 True를 출력하요 or은 둘 중 하나만 참이여도 True를 출력합니다. 파이썬은 예외적으로 소괄호를 써서 우선순위를 뒤로 미루는 경우를 제외하고는 먼저 써진 순서대로 우선 처리 순위를 잡기 때문에 위 코드가 성립할 수 있습니다.
    • A and B에서 A가 1이면 무조건 B값을 따르고 A and B에서 A가 0이면 단락평가에 의해 B는 보지않고 and 연산이 0으로 종료되어 그 다음의 0 or B 연산으로 넘어가는 것
  • num%2가 0이 아닐 때만 True 이기 때문에 Odd가 되고 그 외에는 Even!! (num % 2 and 'Odd') or 'Even'
    • num % 2가 거짓(0)이라면 num % 2 ==0 (거짓) and Odd 가 되므로, 둘 다 참이어야하는 조건에 맞지 않기 때문에 or Even으로 해서 둘 중에 하나라도 참일 때 가능한 Even이 출력되며 , num%2가 1(참)이면 and 조건이 성립되어 Odd가 출력됩니다.
    • if (1)이면 if (True) 형태라서 실행되는 것 (나머지가 있냐(1) 없냐(0))
    • 참고: Python의 Truthy, Falsey
def evenOrOdd(num):
    return ["Even", "Odd"][num & 1]
  • 이진 비트가 1번째 비트 자리에 의해 홀짝이 결정되니 & 연산자로 0 과 1을 구해 리스트 인덱스로 처리
    • & 연산자로 비트 연산한 후 그 수가 ["Even", "Odd"] 배열의 인덱스가 된 것
    • 한자리 수는 한자리 비트만 연산됨
    • 참고: using bitwise operators
  1. return에 바로 if 쓸 수 있음
def evenOrOdd(num):
    return "Even" if num%2==0 else "Odd"

데이터 리터러시

1-2 문제 정의

데이터 분석 파이썬 종합반

1-2 환경 세팅하기 ~ 1-5 변수와 데이터 타입

ADsP 자격증 챌린지

5주차

Article Study

데이터 분석가가 되고 싶은 취준생을 위한 안내서

profile
2 B R 0 2 B

0개의 댓글