프로그래밍/MySQL

[MySQL] SQL ZOO SELECT within SELECT 답 해설

모영이 2021. 2. 20. 00:53

 

SELECT within SELECT Tutorial - SQLZOO

This tutorial looks at how we can use SELECT statements within SELECT statements to perform more complex queries. namecontinentarea populationgdp AfghanistanAsia6522302550010020343000000 AlbaniaEurope28748 2831741 12960000000 AlgeriaAfrica2381741 37100000

sqlzoo.net

#1 Bigger than Russia

러시아의 인구를 가져와서 모든 나라의 인구와 비교, 러시아 인구수 보다 크면 name 데이터 출력

SELECT name 
FROM world
WHERE population > (SELECT population 
                    FROM world
                    WHERE name='Russia')

 

#2 Richer than UK

영국의 인당 GDP값을 가져와서 대륙이 유럽인 나라의 인당 GDP 값과 비교 영국 보다 크면 name 데이터 출력

SELECT name 
FROM world
WHERE continent = 'Europe' AND 
      gdp/population > (SELECT gdp/population
                        FROM world
                        WHERE name = 'United Kingdom')

 

#3 Neighbours of Argentina and Australia

아르헨티나와 호주가 포함 된 대륙과 같은 대륙인 나라의 이름과 대륙을 출력한다.

서브 쿼리의 선택된 continent값이 두개이기에 IN을 사용해야 한다. =을 사용하면 안된다. 

이름 순으로 정렬한다. 

SELECT name, continent 
FROM world
WHERE continent IN (SELECT continent 
                    FROM world
                    WHERE name IN ('Argentina','Australia'))
ORDER BY name

 

#4 Between Canada and Poland

캐나다 인구수보다 크고 폴란드 인구수보다 작은 나라의 이름과 인구수를 출력한다.

SELECT name, population 
FROM world
WHERE population > (SELECT population 
                    FROM world
                    WHERE name = 'Canada') AND 
      population < (SELECT population 
                    FROM world
                    WHERE name = 'Poland')

 

#5 Percentages of Germany

유럽 대륙의 모든 나라를 독일의 인구수로 나눈 인구수 값에 백분률을 해주고, 반올림을 해준다. 그 값이 %를 붙여 준다.

ROUND함수로 반올림을 하고, CONCAT함수로 문자를 덧붙인다.

SELECT문에 서브 쿼리를 사용한다.

SELECT name, CONCAT(ROUND(population/(SELECT population 
                                      FROM world
                                      WHERE name = 'Germany')*100,0),'%')
FROM world 
WHERE continent = 'Europe'

 

#6 Bigger than every country in Europe

유럽의 모든 나라의 GDP를 비교해 보고 그것보다 높은 나라의 이름을 출력한다. 

ALL을 사용해서 서브쿼리의 모든 데이터 값을 비교해서 참일 경우를 판단한다.

만약 ALL을 붙이지 않는다면 서브쿼리의 선택된 값들은 여러개 이므로 10 > (1, 2, 3, 4, 5, 6, 7) 이렇게 되는데 옳지 않은 문법이다. 10 > ALL(1, 2, 3, 4, 5, 6, 7) 이렇게 해주어야 한다.

서브쿼리 앞에 붙이는 것들은 IN, ANY, SOME, ALL, EXISTS 이렇게 있다.

SELECT name
FROM world
WHERE gdp > ALL(SELECT gdp 
                FROM world 
                WHERE gdp > 0 AND continent ='Europe')

 

#7 Largest in each continent

같은 대륙 내의 가장 큰 넓이 값을 가진 나라의 대륙과 이름과 넓이를 출력한다.

AS를 사용해서 메인 쿼리의 world -> x로 치환, 서브 쿼리의 world -> y로 치환한다. AS는 생략이 가능하다.

서브 쿼리에서 y의 대륙과 x의 대륙이 같은 나라의 넓이 값을 가져와 x의 넓이 값과 비교한다.

y의 모든 나라를 가져와서 비교해야하므로 ALL을 사용한다.

SELECT continent, name, area 
FROM world x
WHERE area >= ALL(SELECT area 
                  FROM world y
                  WHERE y.continent = x.continent AND area >0)

 

#8 First country of each continent (alphabetically)

같은 대륙 내 알파벳 순 제일 빠른 이름의 대륙과 이름을 출력한다.

서브 쿼리에서 같은 대륙의 이름 값을 가져오고 그 값을 메인 이름과 비교해서 제일 빠른 이름을 찾아낸다. 

SELECT continent, name 
FROM world x
WHERE name <= ALL(SELECT name 
                  FROM world y
                  WHERE y.continent = x.continent)

 

#9 Difficult Questions

문제는 모든 국가의 인구가 25000000 미만인 대륙을 찾은 다음, 이 대륙과 관련된 국가의 이름을 찾는 것이다.

카리브해와 오세아니아 대륙만 25000000 미만이고 그 대륙에 포함된 나라의 이름을 출력하면 된다.

x의 대륙과 같은 대륙을 찾아내고 그 대륙의 나라의 모든 인구수를 비교한다.

이렇게 하면 x의 각 대륙의 모든 인구수를  비교할 수 있다. ALL은 AND조건을 거는 것과 같으므로.

25000000 >= ALL(유럽 나라1 인구수, 유럽 나라2 인구수, 유럽 나라3 인구수 ...) -> 통과 안됨

25000000 >= ALL(카리브해 나라1 인구수, 카리브해 나라2 인구수, 카리브해 나라3 인구수 ...) -> 카리브해 통과!

25000000 >= ALL(영국 나라1 인구수, 영국 나라2 인구수, 영국 나라3 인구수 ...) -> 통과 안됨

이런 식이다.

조금 복잡한 것 같다..

SELECT name, continent, population 
FROM world AS x
WHERE 25000000 >= ALL(SELECT population
	                FROM world y
		        WHERE x.continent = y.continent
                        AND y.population>0)

 

#10 Difficult Questions

함정이 깊어서 좀 헤맸다. 9번 문제보다 이해는 더 쉬운 것 같다. 9번 문제는 뭐랄까. 무슨 소리하는지 모르겠는 느낌이었다. 이 문제는 같은 대륙의 나라의 인구수 3배 한 값보다 큰 나라를 출력하면 된다. 

이웃 대륙이기 때문에 x.name과 y.name이 같으면 빼줘야 한다. 그렇지 않으면 러시아 인구 >= 러시아 인구 *3 이라는 말도 안되는 식의 조건을 걸게 되어 답이 출력되지 않는다. 

SELECT name, continent
FROM world AS x
WHERE population >= ALL(SELECT population*3
	                  FROM world y
		          WHERE x.continent = y.continent
                          AND y.population>0 AND x.name != y.name)

 

정리하기

서브쿼리를 사용하면 할 수록 반복문 느낌이 강하게 들었다. SELECT를 한번 하고 SELECT를 또 하면 이중 for문을 도는 것하고 비슷한 것 같다.

(SELECT 서브쿼리) : SELECT문, FROM문, WHERE문 등등에 사용할 수 있다.

IN : 리턴 값 중 하나라도 만족하면 참이다.

ALL : 리턴 값 모두를 만족해야 참이다.

ANY, SOME : 리턴 값 중 하나라도 만족하면 참이다.

EXISTS : 리턴 값 중 하나라도 만족하면 참이다.
AS : 치환