ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 프로그래머스 MySQL 고득점 Kit 풀이 정리
    MySQL 2021. 3. 3. 13:05

    MAX/MIN

    최소/최댓값

    SELECT MAX(컬럼) FROM 테이블;
    SELECT MIN(컬럼) FROM 테이블;

    다만 컬럼 이름이 MAX(컬럼) 처럼 나오기 때문에 원하는 컬럼명이 있다면 MAX(컬럼) as '원하는 컬럼명'처럼 써야한다.

     

     

    COUNT

    데이터 ROW 개수

    SELECT COUNT(*) FROM 테이블;

     

    ROW 개수를 세는데, 특정 컬럼에 중복값이 있고, 그건 빼고 세고싶다면 DISTINCT를 쓰면 된다.

    NULL 값과 중복된 값은 제외하고 세준다.

    SELECT COUNT(DISTINCT 컬럼) 테이블;

     

    중복은 빼되 NULL은 포함해야 한다면

    SELECT COUNT(*) FROM (SELECT * FROM 테이블 GROUP BY 컬럼)sub; 

     

     

    GROUP BY, HAVING

    특정 컬럼에 특정 데이터가 몇 개씩 있는지 알고 싶다면 [정렬은 옵션]

    SELECT 컬럼, COUNT(*) FROM 테이블 GROUP BY 컬럼 [ORDER BY 컬럼 ASC];

     

    그중에 중복인 데이터가 몇 개인지 알고 싶다면(해당 데이터 개수가 한 개 초과인 경우라면) [정렬은 옵션]

    HAVING을 쓰면 그룹으로 묶은 다음에 조건을 계산해준다.

    SELECT 컬럼, COUNT(컬럼) as CNT FROM 테이블 GROUP BY 컬럼 HAVING CNT>1 [ORDER BY 컬럼];

     

     

    NULL

    NULL은 = NULL이 아니고 IS NULL로 검색해야 한다.

    SELECT 컬럼 FROM 테이블 WHERE 컬럼 IS NULL;

     

    IS NULL의 반대는 IS NOT NULL

    SELECT 컬럼 FROM 테이블 WHERE 컬럼 IS NOT NULL;

     

    NULL값을 다른 값으로 대체해서 가져오고 싶다면

    SELECT IFNULL(컬럼, '대체값'), FROM 테이블;

     

     

    JOIN

    테이블이 2개일 때, 한 테이블에만 있고 다른 테이블에는 없는 값을 가져오고 싶다면

    /* 테이블1: 빠진 데이터가 "없는" 테이블
       테이블2: 빠진 데이터가 "있는" 테이블 */
    SELECT 테이블2.외래키, FROM 테이블1
      RIGHT OUTER JOIN 테이블2 ON 테이블1.외래키 = 테이블2.외래키
      WHERE 테이블1.외래키 IS NULL;

    위의 쿼리를 LEFT JOIN으로 쓰고 싶다면 순서를 바꿔주면 된다.

    SELECT 테이블2.외래키, FROM 테이블2
      LEFT OUTER JOIN 테이블1 ON 테이블2.외래키 = 테이블1.외래키
      WHERE 테이블1.외래키 IS NULL;

    다만 값이 없는 테이블이 테이블1이니, IS NULL은 테이블1로, SELECT할 데이터는 테이블2로 걸어주어야 한다.

     

    위와 반대로 테이블1에 데이터가 있고, 테이블2에 없는 경우는 아래와 같이 된다.

    ORDER BY와 LIMIT를 같이 쓸 경우 순서는 이렇다.

    /* 테이블1: 빠진 데이터가 "있는" 테이블
       테이블2: 빠진 데이터가 "없는" 테이블 */
    
    SELECT 테이블1.컬럼, 테이블1.정렬기준컬럼 FROM 테이블1
      LEFT OUTER JOIN 테이블2 ON 테이블1.외래키 = 테이블2.외래키
      WHERE 테이블2.외래키 IS NULL
      ORDER BY 테이블1.정렬기준컬럼
      LIMIT 3;

     

     

    다른 테이블의 컬럼 정보를 기준으로, 그보다 크거나 작은 컬럼만 보고 싶다면

    SELECT 테이블1.외래키 FROM 테이블1
      LEFT JOIN 테이블2 ON 테이블1.외래키 = 테이블2.외래키
      WHERE 테이블2.비교컬럼 < 테이블1.비교컬럼
      ORDER BY 테이블1.비교컬럼;

     

    단순히 값이 같지 않은 컬럼을 확인하고 싶다면 이렇게 하면 된다.

    SELECT 테이블1.외래키 FROM 테이블1
      LEFT JOIN 테이블2 ON 테이블1.외래키 = 테이블2.외래키
      WHERE 테이블1.비교컬럼 != 테이블2.비교컬럼;

     

    두 컬럼을 연산한 결과를 기준으로 정렬할 수도 있다.

    SELECT 테이블1.외래키 FROM 테이블1
      LEFT JOIN 테이블2 ON 테이블1.외래키 = 테이블2.외래키
      ORDER BY (테이블2.연산대상컬럼 - 테이블1.연산대상컬럼) DESC  /* 연산결과가 큰 순서대로 */
      LIMIT 2;                                           /* 위에서 2번째 항목까지만 출력 */

     

     

    WHERE IN

    특정 컬럼의 값이 리스트에 포함되어 있는지를 확인하고 싶다면 WHERE IN을 쓰면 된다.

    SELECT 기본키, 대상컬럼 FROM 테이블
      WHERE 대상컬럼 IN ('조건1', '조건2', '조건3')
      ORDER BY 기본키;

     

     

    LIKE

    특정 컬럼의 값이 특정 문자열을 포함하고 있는지를 확인하려면, LIKE 문을 쓴다.

    SELECT 컬럼 FROM 테이블
      WHERE 컬럼 LIKE '%대상문자열%';

    %는 임의의 문자열에 매치되기 때문에, 포함만 하고 있으면 된다면 '%문자열%'처럼 앞뒤에 임의의 문자열이 오도록 하고,

    문자열로 끝나야 한다면 '%문자열', 문자열로 시작해야 한다면 '문자열%'처럼 쓰면 된다.

     

     

    매칭한 결과에 따라서 True, False을 표시하고 싶다면 IF문을 받는 컬럼을 추가해준다.

    SELECT IF(대상컬럼 LIKE '문자열1%' OR 대상컬럼 LIKE '문자열2%', True, False) as '연산결과'
      FROM 테이블;

    위 쿼리문은 정규식을 이용해서 아래처럼 표현할 수도 있다.

    (REGEXP, RLIKE, REGEXP_LIKE는 같은 개념이다.)

    SELECT IF(대상컬럼 REGEXP '문자열1|문자열2', True, False) as '연산결과' FROM 테이블명;
    SELECT IF(대상컬럼 REGEXP('문자열1|문자열2'), True, False) as '연산결과' FROM 테이블명;
    SELECT IF(대상컬럼 RLIKE '문자열1|문자열2', True, False) as '연산결과' FROM 테이블명;
    SELECT IF(대상컬럼 RLIKE('문자열1|문자열2'), True, False) as '연산결과' FROM 테이블명;
    SELECT IF(REGEXP_LIKE(대상컬럼, '문자열1|문자열2'), True, False) as '연산결과' FROM 테이블명;

    '문자열1%|문자열2%'이나 '(문자열1|문자열2)%'이 아닌 이유는

    REGEXP, RLIKE, REGEXP_LIKE()는 패턴이 문자열에 매치되는가를 확인하기 때문이다. 시작부터 끝까지가 같은가가 아니다.

    아래는 MySQL 도큐먼트 예제

    mysql> SELECT REGEXP_LIKE('aXbc', '[a-dXYZ]');                 -> 1

     

     

    DATETIME

    DATETIME 데이터는 HOUR 함수를 이용하면 시간대 별로 묶어서 특정 시간대의 데이터만 확보할 수도 있다. [정렬은 옵션]

    SELECT HOUR(DATETIME) as HOUR, COUNT(*) AS HOUR_COUNT FROM 테이블
      GROUP BY HOUR(DATETIME) HAVING HOUR >= 시작시각 and HOUR < 종료시각 [ORDER BY HOUR];

     

    내 데이터에는 7~21시까지의 데이터밖에 없는데, 결과는 0~24시로 보고 싶다면,

    새로 0~24까지의 데이터가 있는 테이블을 만들어주거나, 임시로 사용할 가상테이블을 만들어줘야 한다.

    SELECT와 UNION으로 가상테이블을 만드는 방법은 이쪽을 참조했다: darammg.tistory.com/8

    WITH은 이쪽: wakestand.tistory.com/455

    WITH tempHour AS (
      (SELECT 0 as hour) UNION
        (SELECT 1) UNION
        (SELECT 2) UNION
        (SELECT 3) UNION
        (SELECT 4) UNION
        (SELECT 5) UNION
        (SELECT 6) UNION
        (SELECT 7) UNION
        (SELECT 8) UNION
        (SELECT 9) UNION
        (SELECT 10) UNION
        (SELECT 11) UNION
        (SELECT 12) UNION
        (SELECT 13) UNION
        (SELECT 14) UNION
        (SELECT 15) UNION
        (SELECT 16) UNION
        (SELECT 17) UNION
        (SELECT 18) UNION
        (SELECT 19) UNION
        (SELECT 20) UNION
        (SELECT 21) UNION
        (SELECT 22) UNION
        (SELECT 23)
    )

    WITH으로 만든 테이블을 실행해보면

    SELECT hour FROM tempHour;
    /*
    hour
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    */

    이제 이 가상테이블을 원래 테이블과 붙여서 원하는 결과를 출력해주면 된다.

    SELECT tempHour.hour as 'HOUR', IFNULL(cnt, 0) as 'COUNT'
      /* 최종적으로 필요한 건 HOUR, COUNT고, 7~21시를 벗어나는 범위는 NULL이므로 값을 0으로 지정한다 */
      FROM ( /* 데이터를 가져올 테이블을 생성한다 */
          SELECT HOUR(DATETIME) as hour, COUNt(*) AS cnt FROM 테이블
            GROUP BY HOUR(DATETIME) /* 시간대 별로 묶어서 서브쿼리를 만들고 */
          )sub
          RIGHT JOIN tempHour  /* 없는 범위도 출력되도록 위에서 만들어둔 가상테이블과 합친다 */
          ON sub.hour = tempHour.hour;

     

     

     

    추가로 포매팅이 필요하다면 DATE_FORMAT 함수를 쓴다.

    /* 2자리년도 - 숫자월 - 숫자일 */
    SELECT DATE_FORMAT(DATETIME, '%y-%m-%d') FROM 테이블;  /* 21-03-03 */
    /* 문자월 - 일th, 4자리년도 */
    SELECT DATE_FORMAT(DATETIME, '%M %D, %Y') FROM 테이블; /* March 3rd, 2021 */

     

    댓글

Designed by Tistory.