해당 문제는 아래 링크에서 더 자세히 참고하실 수 있습니다.
https://www.hackerrank.com/challenges/print-prime-numbers/problem?h_r=internal-search
문제 : 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-지정하기
'프로그래밍 언어 > SQL' 카테고리의 다른 글
[MySQL] 한 행 안에 있는 문자열 여러 개를 행으로 분리하기 (0) | 2022.01.14 |
---|---|
[Hackerrank] Weather Observation Station 5 (0) | 2022.01.13 |
[프로그래머스 SQL 문제] 루시와 엘라 찾기 (0) | 2021.08.25 |
[프로그래머스 SQL 문제] 보호소에서 중성화한 동물 (0) | 2021.08.10 |
[프로그래머스 SQL 문제] 오랜 기간 보호한 동물(1) (0) | 2021.08.10 |