sql

sqlzoo - SELECT in SELECT

yjs3819 2021. 7. 17. 15:13
728x90

SQL

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

SELECT population FROM world where name = 'Russia' 서브쿼리의 결과는 단일 값이다. 즉 위의 쿼리는

SELECT name FROM world  
WHERE population >  
146745098;

아래 쿼리와 같다.

  1. select name from world  
    where continent = 'Europe' AND gdp / population >  
    (select gdp / population from world where name = 'United Kingdom');

서브쿼리는 차근차근 쿼리를 짜나가면된다.
select gdp / population from world where name = 'United Kingdom' 의 결과 값도 단일 값이다.

3.
먼저 아르헨티나와 오스트레일리의 대륙을 찾는다
select continent from world where name IN ('Argentina ', 'Australia');
이대륙의 이름과 이대륙의 나라를 조회해야한다. 위 쿼리의 결과는 'Oceania', 'South America'의 두개의 값이다. 두개의 레코드가 결과다. 이전과 다르다라는걸 인지하자

IN연산자를 써서 두 레코드값중 하나에 해당되는 결과를 뽑아보자

select name, continent from world where  
continent in (select continent from world where name IN ('Argentina ', 'Australia'))  
order by name ASC;

단일 값과 는 다르게 서브쿼리의 결과가 두개의 레코드 값이므로 =, >, < 과같은 연산자를 직접 사용할수없다.
위 연산자를 쓰려면 ALL, ANY로 다중 결과중 몇개를 연산자의 대상으로 쓸지 지정을해줘야한다.
혹은 IN, EXISTS와 같이 다중 레코드중 포함이되면 참을 반환하는 IN과, 해당 서브쿼리의 결과값이 존재하는지 아닌지에 따라서 참 거짓을 반환하는 EXISTS등의 함수를 써야한다.

  1. select name, population from world  
    where population > (select population from world where name = 'Canada')  
    AND population < (select population from world where name = 'Poland');

    위 subquery들의 결과는 단일 레코드이다.

  2. select name,  
    CONCAT(ROUND(population / (select population from world where name = 'Germany') * 100, 0), '%') as percentage from world  
    where continent = 'Europe';

    하나씩 해보자
    먼저 독일의 인구를 알아야하므로 독일의 인구를 조회할 서브쿼리를 이용한다. select population from world where name = 'Germany'
    그리고 유럽 나라의 인구로 나누고 * 100을해야 퍼센트가 나오고 그리고 0의자리에서 반올림을 한다. 그뒤 CONCAT 함수로 뒤에 %를 붙이면 완성이다! (AS로 해당 칼럼의 별명까지 붙여주면 완전완성!)

  3. select name from world where gdp >  
    (select MAX(gdp) from world where continent = 'Europe');

    유럽의 최대 gdp를 서브쿼리로 구하고 where절에 추가하면된다. 서브쿼리 결과는 하나의 레코드이다.

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

    부모 쿼리의 continent와 같으면서 area > 0인 area만 프로젝션하는 서브쿼리는
    부모쿼리의 continent가 Asia라면 Asia의 모든 area의 레코드가 결과값일 것이다. 다중 레코드가 결과값임을 유의하자
    여기서 ALL 연산자로 다중 레코드를 연산할건데, ALL은 다중레코드와 연산의 결과가 모두 참이여야한다. 연산의 대상을 모든 레코드로 지정한 것이다. 즉, area >= ALL (다중레코드)가 참이려면 부모쿼리의 area가 다중레코드인 area들 보다 모두 크거나 같아야한다. 즉, 최대값일 경우 참이다.

그러므로 굳이 ALL을 쓰고싶지않다면 서브쿼리의 결과가 단일 레코드인 최대 area 값이 나오도록 조금만 수정하면된다.

SELECT continent, name, area FROM world x
  WHERE area >=
    (SELECT MAX(area) FROM world y
        WHERE y.continent=x.continent
          AND area > 0)
  1. select continent, name from world x
    where name = 
     (select name from world y where x.continent = y.continent order by name ASC limit 1);

    부모쿼리의 continent와 같은 다중 레코드들중, 이름을 알파벳순으로 정렬하고 limit으로 한개만 페이징한 서브쿼리의 결과는 단일레코드이다.
    이 값과 같은 continent와 name을 조회하면됨

  2. select name, continent, population from world 
    where continent in
    (select distinct continent from world x 
     where 25000000 >= ALL(select population from world y where x.continent = y.continent));

    복잡한 서브쿼리지만 하나씩 해나가면 쉽다.
    먼저 같은 대륙끼리 비교해야하므로 부모쿼리의 continent와 자식쿼리의 continent가 같은 조건의 서브쿼리를 이용해서 같은 대륙끼리 비교하도록 한다.
    그리고 서브쿼리의 결과가 다중 레코드값일 테니 ALL연산자로 모두 해당 조건에 맞는지 검사를 한다.
    select distinct continent from world x where 25000000 >= ALL(select population from world y where x.continent = y.continent)
    distinct로 중복을 제거하면 하나의 단일 레코드값이 나온다. 그러나 어떠한 값이 모른다는 가정을 한다면 in을 쓰는것이 적절하다.

ALL을쓰기 싫다면 조금만더 생각해서 모든 대륙의 인구가 25000000보다 작거나 같아야하므로 각 대륙의 최대 인구수가 25000000보다 작은 조건만 생각해도 된다.

select name, continent, population from world 
where continent in
  (select distinct continent from world x 
    where 25000000 >= (select MAX(population) from world y where x.continent = y.continent));

위의 쿼리와 다른점은 제일 내부의 서브쿼리는 단일 레코드값을 리턴한다는 것이다.

  1. select name, continent from world x
    where population > ALL(select population * 3 from world y where x.continent = y.continent AND 
                         x.name <> y.name);
    10번도 같은 continent끼리 비교를 해야한다. 그래서 상관쿼리를 이용한다.(대륙이 같은 조건)
    추가로 이문제는 같은 나라끼리는 비교하면 안되기때문에 AND조건문으로 이름이 다른 조건을 추가 하였다.
    같은 대륙중 다른 모든 나라보다 3배 이상 큰 인구를 가진 나라와 그 나라의 대륙을 조회하는 문제이다.

quiz

  1. 3
  2. 2
  3. 1
  4. 4
  5. 2
  6. 2
  7. 2
728x90

'sql' 카테고리의 다른 글

sqlzoo - SUM and COUNT  (0) 2021.07.23
sqlzoo - SELECT from nobel  (0) 2021.07.16
sqlzoo - SELECT from World  (0) 2021.07.15
sqlzoo - SELECT basics  (0) 2021.07.14