본문 바로가기
  • think normal
새로워지기/서른의 생활코딩

삼팔광땡 MYSQL 입문기 04 - 서브쿼리

by 청춘만화 2019. 2. 12.

삼팔광땡~ MYSQL 입문기 04


자, 이제 두번째 걸음이다.  무 밭에 도착했으니 이제 뽑을 만한 무를 골라보자. 

아, 미리 언지를 드리면 실습에 사용되는 테이블은 동일하지만 책에서 설명하고있는 예제와는 똑같지는 않습니다.  >< 


0. 이런 실수? 할 수 있다.
 

비전공자 또는 낙엽줄로 개발 공부하면서 섭섭하게 느끼는 점이 하나 있다면 너무 당연?한 것은 알려주지 않는다는 것이다. 매번 포스팅을 작성하기 앞서 그런 내용들을 기억나는 데로 적어두려한다. 

1) 아직 기억나는 내용이 없어 대기 중 입니다.


1. 서브쿼리(1) 

서브쿼리 oracle을 한바뀌 돌아본 입장에서 이녀석 중요한 녀석이다. 책으로 보면 중간을 살짝 넘어간 자리에 위치해있다. 자 이제 시작이란 느낌적인 느낌으로 고 해보자.

서브쿼리는 

- select 명령에 의한 데이터 질의로, <-- select 절에서 사용한다는 뜻 아닙니다 ;D   서브쿼리가 select절 로 구성되어 있다는 말씀~

- 상부가 아닌 하부의 부수적인 질의를 의미 한다고 합니다.

- 주로 where 절에서 많이 사용된다.

- 참고로 where 절은 select, delete, update 구에서 사용할 수 있습니다.


넘어가기 전에 구글링을 해보니 다른 블로그에서는 이렇게 정리되어 있네요 

하나의 쿼리문 안에 포함되어 있는 또 하나의 쿼리문을 말합니다. 

서브쿼리는 메인쿼리가 서브쿼리를 포함하는 종속적인 관계입니다. 

여러번의 쿼리를 수행해야만 얻을 수 있는 결과를 하나의 중첩된 SQL문장으로 간편하게 결과를 얻을 수 있게 해줍니다. 

쉽게 말해서 쿼리문안에 쿼리문을 또 쓴다고 생각하면 됩니다. 

※ Sub Query 를 Inner Query라고도 합니다.

링크를 걸어두었으니 관심있으신 분들 방문해보세요, 예제도 있습니다.


1) 실습에 앞서 예제용 테이블을 확인해보겠습니다.

 select * from sample54; 


2) delete 구에서 서브쿼리 사용해보기. 

(1) 그런데 말입니다. 이거 조금 어렵습니다. 일단 앞에서 정의한 서브쿼리 형태로 만들면 아래 문장이 되거든요. 그런데 실행해보시면 다음과 같은 에러가 뜹니다. 

delete 
from 
  sample54 
where 
  a=(select min(a) from sample54); 


(2) 책에서는 변수를 사용하거나 delete 구문을 selecet 구문으로 바꾸라고 합니다... 전자는 MySQL에서 밖에 못쓰는 문법이고요.. 후자는 말도 안되는 대안이죠.. 요구사항이 바뀌는 거니까... 그래서 구글링을 해보니. 아래와 같이 그 원인을 설명하고 있었습니다. 해결방안은 링크다고 가시면 나와 있습니다. 

MySQL 은 Oracle 과는 달리 UPDATE 나 DELETE 시 자기 테이블의 데이타를 바로 사용 못하므로 아래와 같은 SQL 을 실행시 1093 에러가 발생함.(링크 고고~)


        위에 블로그에서 제안한 가이드를 참고해서 수정한 쿼리 입니다. 돌아가네요 ^^ 감사 감사, 저도 누군가에게 이렇게 도움이 되는 블로그면 좋겠네요 ㅎㅎㅎ 분발! 분발! 

delete 
from 
  sample54 
where 
  a=(select * from 
              (select min(a) from sample54) tmp
    ); 

수정한 코드를 설명하면, 

MySQL이 자기 테이블의 데이타를 바로 사용 못한다고 하니..

이전처럼 a와 서브쿼리를 바로 비교하는 것이 아니라,  

서브쿼리를  (select * from tmp); 로 한번 감싸고나서 비교하고 있습니다. 

 select * from sample54; 


3) 스칼라 - 이름음 멋있는데 왠지 어려워 보이는 단어 입니다. 풀이하면 select에 의한 결과로 하나의 값만 반환되는 것을 말하고요. 이를 '스칼라 값을 반환한다'고 말한다고 합니다. 결국 값이 하나 라는 거죠. 굳이 왜 이름을 붙였을까요? 이유는 서브쿼리에서 요기나게 쓰여서 그렇다고 합니다. 메인쿼리를 위해 서브쿼리로 조건을 만드는데 그 조건이 여러개이면 메인뭐리에서 비교하기가 애매하겠죠? ... 말이 되는 말인가? 대략 느낌적인 느낌은 그렇습니다만... 

뭔가 아쉬워 구글링을 해보면, 자료가 별로 없네요.. 관련 유튜브가 하나 눈에 띄어서 링크를 걸어둡니다.


4) select 구에서 서브쿼리 사용해보기

문법적으로 서브쿼리는 '하나의 항목'으로 취급합니다. 단 문법이 맞다고 에러가 없는건 아닙니다. 말을 할 수 있다고 다 맞는 말인 건 아니니까요 ㅎ 그래서 스칼라 서브쿼리가 필요한거죠. 물론 select 구에서 서브쿼리를 지정할때도 스칼라 서브쿼리가 필요합니다. 다시말해 하나의 값을 반환하는 서브쿼리가 필요한거죠.

아래 예제는 각 테이블의 갯수를 반환하는 서브쿼리 두개로 이뤄진 select문입니다. 갯수니까 당연히 값은 1개. 스칼라 값을 반환하는 서브쿼리다 라고 할 수 있겠죠.

select
  (select count(*) from sample51) as sq1,
  (select count(*) from sample54) as sq2 
from 
  dual; 

α )   dual은 시스템 쪽에서 데이터베이스에 기본으로 작성되는 테이블입니다. MySQL에서는 생략이 가능하긴합니다...만 그냥 쓰죠 ;D


5) update set 구에서 서브쿼리 사용해보기 - 이번엔 예제 테이블에서 가장 큰 값으로 테이블을 도배(update set)? 해볼까요?

update 
  sample54 
set 
  a=(select * from 
             (select max(a) from sample54) tmp
); 
 select * from sample54; 



6) from 구에서 서브쿼리 사용해보기 - 희소식? 입니다. from 구에서의 서브쿼리는 스칼라 값이 아니어도 됩니다. 왜냐면은 말이죠. 느낌이 오시죠? from 구에서의 서브쿼리는 거르기 위한 필터 역할이 아니라 고르기위한 바구니 역할을 하기때문이 아닐까요?  라고 이해했습니다. 

select * from 
         (select * from sample54) sq; 
 select * from sample54; 

음.. 결과가 안이쁘네요.. 이전에 MAX로 도배를 해놔서.. 책에서는 예제로 올려두고 실행은 안하셨네요.. 결과가 달라욥.. 흑,,    

α )   참고로 from 구에서는 잘 사용하지는 않지만, 굳이 사용한다면 같은 절에서 연달아 3단계 까지로도 서브쿼리를 중첩해서 쓸수도 있다고 합니다. 쿼리는 아래와 같습니다. 결과는 동일합니다. 

select * from 
         (select * from
                   (select * from sample54) sq1) 
          sq2; 

α )   참고로 현업에서는 위와 같이 서브쿼리로 도출해된 리스트를 재정렬 한 후 상위 몇개만 뽑아 쓰는 쿼리를 자주 쓴다고 합니다. 아래 예제처럼말이죠. 물론 아래 예제 테이블의 값으로는 정렬이 의미가 없지만.. 느낌적인 느낌으로 아,이런거구나- 하고 이해해주셔도 좋을 것 같습니다.

select * from 
 (select * from sample54 order by a desc) sq
limit 2; 


α )   추가적으로 ORACLE 에서는 limit가 아닌  where rownum<=원하는 리스트 개 과 같이 사용하는거 기억하시죠? 

select * from 
 (select * from sample54 order by a desc) sq
where rownum <= 2; 



7) insert 구에서 서브쿼리 사용해보기

시작에 앞서 참고로 sample541은 먼저 확인해 본 결과,  빈 테이블입니다.

(1) 서브쿼리는 스칼라 서브쿼리여야하고  insert의 values는 각 컬럼의 자료형과 일치해야합니다.

insert into
  sample541 
values (
  (select count(*) from sample51),
  (select count(*) from sample54)
);
 select * from sample541; 


(2) 아래와 같이 서브쿼리를 활용하는 방법도 있습니다. 이름하여 insert select 

a) insert into sample541 values(1,2) 와 동일

 insert into sample541 select 1,2; 

b) select 명령의 결과를 insert into 로 지정한 테이블에 전부 추가합니다. select 명령의 결과를 클라이언트로 반환하지않고 지정된 테이블에 추가하는 거죠. 데이터를 복사하거나 이동하는 경우 주로 사용됩니다. 복사하는 대상 테이블과 열 구성 및 자료형이 같다면 행 자체를 복사할 수도 있습니다.

 insert into sample542 select * from sample543; 


그런데.. 책에 있는 예제는 실행이 안되네요..혹시 오탈까 해서 숫자를 바꿔도 안되네요.. 없는 테이블이라는거 같죠? ;> 

그래서 구글링 해보았습니다. W3schools에 예제가 있네욥  링크 걸어두었으니 시간되시는 분은 들려보세용~



음.. 다음은, 음.. 


둠-칫- 

배고프네..

오늘은 여기까지~ ;D 


댓글