본문 바로가기
프로그래밍 언어/SQL

[Hackerrank] Print Prime Numbers 풀이 (MySQL)

by gokite 2022. 1. 13.

해당 문제는 아래 링크에서 더 자세히 참고하실 수 있습니다.

https://www.hackerrank.com/challenges/print-prime-numbers/problem?h_r=internal-search 

 

Print Prime Numbers | HackerRank

Print prime numbers.

www.hackerrank.com

문제 : 1000이하의 소수를 모두 출력해라.

조건 :

 1. 여러 행에 걸쳐 모든 수를 출력하는 것이 아닌, 한 행에 모든 수를 & 구분자로 출력할 것

 

예상 답안 : 

2&3&5&7

 (10이하의 소수점을 출력했을 때)

 

 

 

테이블이 없는데..어떻게 풀지?

문제를 풀기 앞서, 가장 황당한 점은 나에게 주어진 테이블이 아무 것도 없다는 것이었다.

이런 경우 모든 데이터베이스에 기본적으로 적재되어 있는 "Information_schema"를 사용하면 된다.

 

Information_schema는 정보스키마라고 불리며 MySQL에 존재하는 메타 데이터들을 테이블화 시킨 뒤, 이 테이블을 모아놓은 데이터베이스라고 생각하면 된다. 예를 들어보자. A라는 테이블이 있다. 이 테이블은 DATA라는 데이터베이스에 적재되어 있고, Data_length가 16384되는 테이블이다. B라는 테이블이 있다. 이 테이블은 DATA2라는 데이터베이스에 적재되어 있고, Data_ length가 592인 테이블이다. 이처럼 각 테이블의 메타데이터 속성을 열로 구성한 데이터테이블이 이 있다.

 

TABLE_NAME DATABASE_NAME DATA_LENGTH
A DATA 16384
B DATA2 592

 이렇게 테이블에 대한 테이블 정보를 모아놓은 테이블이 있을 것이다. (말장난같긴하지만..)

 그러나 메타데이터 정보는 테이블 뿐만 아니라 칼럼 등 다양한 속성에도 필요로 할 것이다. 이런 메타데이터 정보 테이블을 모아놓은 데이터베이스를 정보스키마라고 생각하면 된다. 

 

 

이미지를 보면 더 이해가 쉬울 것이다.

본인 MySQL에서 실행한 결과이다.

USE DATABASE; 를 입력하여 사용할 데이터베이스를 선택하고 해당 테이블을 출력했다.

여러 메타 정보를 담고 있는만큼, information_schema를 이용하면 MySQL에 존재하는 다양한 정보를 쉽게 얻을 수 있다. 추가적으로, 대부분의 INFORMATION_SCHEMA 안의 TABLE들은 읽기 권한만 가지고 있어 인위적인 수정은 불가능하다. 

(그래서 보안도 신경써야하는 부분이라고 한다.)

 

 

요점으로 들어와서, 우리는 주어진 테이블이 없으니 적재되어 있는 정보 스키마를 쓸 것이다. 그 안에 담겨있는 내용을 쓴다기 보단, 틀 자체를 빌려온다고 생각하면 된다. 

 

 

 

서브 쿼리부터 천천히 코드를 풀이해보도록 하겠다.

참고로 해당 풀이의 코드는 

여기를 참고했다.

 

SELECT @num:=@num+1 AS NUMB
      FROM information_schema.tables t1,
           information_schema.tables t2,
           (SELECT @num:=1) tmp

 

 

FROM 부분에 왜 테이블을 연이어 썼지?

우선적으로, 의문이 든 건 두 가지다.

1. JOIN의 표시도 없고 어떻게 연달아서 썼지? 

2. 1번의 이유가 해결된다면, 왜 똑같은 테이블을 두 개나 사용했지?  

 

번째 질문에 대답은 

여기서 얻을 수 있었다.

JOIN을 단순히 명시하지 않은 방식으로 T-SQL? 방식이라고 한다. 내가 공부한 서적에서는 항시 명시되어 있었던 부분이라 새로운 문법인 줄 알았는데 별 차이는 없다고 한다. 표준 방식을 익히는 게 좋다고 하니 이런 게 있구나 하고 넘어가면 될 듯 하다.

 

번째 질문의 답은 테이블 행을 늘리기 위해서다. 1000이하의 소수점을 전부 출력해야하는데, t1 테이블은 364행으로 이루어져있다. 소수의 수가 얼마나 되는 지는 모르겠지만 안전하게 1000개 정도의 행은 있어야 예외없이 처리할 수 있게 행을 늘린 것 뿐이다.

 

 

@num이 뭐지?

파이썬에서 변수를 선언하듯이 MySQL에서도 변수를 선언할 수 있다.

가끔 데이터 분석을 하다보면, 결과값 뿐만 아니라 그 값들의 행의 순번을 봐야할 상황이 있다.

 

ROWNUM RESULT
1 A3523
2 N26462
3 C23523

이렇게 말이다.

여기서 ROWNUM은 테이블내 존재하는 칼럼이 아닌 변수를 선언해서 만들어낸 임시 열이라고 생각하면 된다.

오라클 등의 디비에서는 row_number()를 이용하여 행마다의 순번을 지정할 수 있으나 mysql 에서는 해당 함수가 없다.

대신 아래와 같은 방법을 이용할 수 있다.

set @num:=0;
select @num:=@num+1 as rownum, result from {TABLE} [where];

> @변수:= 설정값 < 으로 변수를 설정할 수 있다. (:=와 =  는 동일하게 사용가능)

위를 보면 NUM 변수를 설정하여 0으로 초기화(SET) 했다. (select로도 초기화할 수 있음)

참고로 선언하거나 초기화하지 않아도 사용할 수 있으며, 그런 경우에 null값이 할당된다.  (select @num)

해당 변수는 DB 연결상태에서 계속 유지 되므로 다른 쿼리에서 사용시 초기화 해줘야 한다.

select 쿼리문의 where 절에서도 초기화가 가능하다.

 

 

=> 해당 쿼리를 통해서 아래와 같은 결과를 얻을 수 있다.

ROWNUM
2
3
4
5

2부터 행 끝까지 1씩 커지는 숫자들로 채워져있다.

이제 소수를 구별할 조건 테이블을 추가할 차례다.

 

 

SELECT GROUP_CONCAT(NUMB SEPARATOR '&')
FROM (SELECT @num:=@num+1 AS NUMB
      FROM information_schema.tables t1,
           information_schema.tables t2,
           (SELECT @num:=1) tmp
      ) tempNum
WHERE NUMB <= 1000
AND NOT EXISTS (SELECT *
                FROM (SELECT @nu:=@nu+1 AS NUMA
                      FROM information_schema.tables t1,
                           information_schema.tables t2,
                           (SELECT @nu:=1) tmp1
                      LIMIT 1000
                      ) tempNum1
                WHERE FLOOR(NUMB/NUMA) = (NUMB/NUMA)
                AND NUMA < NUMB
                AND 1 < NUMA
               )

 

 

1. WHERE FLOOR(NUMB/NUMA) = (NUMB/NUMA) 를 이용하여 소수를 걸러낸다.

2. WHERE NUMB <= 1000 통해 1000미만 소수라는 조건을 만족시킨다

3. GROUP_CONCAT를 이용하여 한 줄에 표기한다.

 

왜 NOT IN을 안쓰고 NOT EXISTS 를 썼을까?

- NOT IN

SELECT * FROM a WHERE a.key NOT IN ( SELECT b.key FROM b )

✔︎ b 테이블을 먼저 접근

✔︎ b.key를 IN 리스트에 나열 후 a.key에 공급

✔︎ b테이블: '공급자 역할'

 

- NOT EXISTS

SELECT * FROM a WHERE NOT EXISTS ( SELECT * FROM b WHERE a.key = b.key )

 

✔︎ a 테이블을 먼저 접근

✔︎ 구해진 a의 row들을 NOT EXISTS절의 b테이블에서 필터링

✔︎ b테이블: '확인자 역할'

 

출처: http://blog.kkomzi.net/128




GROUP_CONCAT은 어떻게 쓰는거지?
DEPARTMENT NAME
HR 이영애
HR 구경이
HR 케이

 

↓GROUP_CONCAT

 

DEPARTMENT NAME
HR 이영애,구경이,케이

 

이럴 때 쓸 수 있다.

 

select department, group_concat(name separator ' ') from tb group by department

- separator를 설정하지 않는다면, 디폴트 값은 , 이다.

 

그외 사용법

1. 기본형 : group_concat(필드명)
2. 구분자 변경 : group_concat(필드명 separator '구분자')
3. 중복제거 : group_concat(distinct 필드명)
4. 문자열 정렬 : group_concat(필드명 order by 필드명)

출처: https://fruitdev.tistory.com/16 [과일가게 개발자]

 

 

 


<참고 사이트>
https://j07051.tistory.com/583
https://webee.tistory.com/entry/select-시-순번row-number-지정하기 

https://webee.tistory.com/entry/select-%EC%8B%9C-%EC%88%9C%EB%B2%88row-number-%EC%A7%80%EC%A0%95%ED%95%98%EA%B8%B0

https://poqw.tistory.com/24