안녕하세요, 아래와 같이 사람의 이름이 있고 지점이 10개가 있다고 가정 할 때
김길동의 경우 8번 지점을 첫번째로, 7번 지점을 두번째로 해서 10번 지점을 마지막으로 방문했다고 가정하면
이렇게 몇번 지점을 순차적으로 방문했는지를 먼저 보여주는 쿼리는 어떻게 접근하면 좋을까요?
툴이 있는 것 같기도 한데.. 일단 고민하다가 고민 올려봅니다...!
꼭 쿼리 답안이 아니더라도 더 고수분들의 좋은 조언을 구해 봅니다!
이름 | 1번쨰 | 2번쨰 | 3번쨰 | 4번쨰 | 5번쨰 | 6번쨰 | 7번쨰 | 8번쨰 | 9번쨰 | 10번쨰 |
김길동 | 3 | 4 | 6 | 8 | 9 | 5 | 2 | 1 | 11 | 14 |
김XX | 13 | 11 | 3 | 7 | 6 | 5 | 2 | |||
박XX | 2 | 6 | 7 | 8 | 3 | 10 | 5 | 9 | ||
최XX | 3 | 5 | 1 | 2 | 9 | 8 | 14 | 15 | 10 | |
이XX | 13 | 15 | 14 | 2 | 9 | 8 | 6 | 4 | 2 | 1 |
-- Oracle -- WITH t(id, nm, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10) AS ( SELECT 1, '김길동', 3, 4, 6, 8, 9, 5, 2, 1, 11, 14 FROM dual UNION ALL SELECT 2, '김XX' , 13, 11, 3, 7, 6, 5, 2, null, null, null FROM dual UNION ALL SELECT 3, '박XX' , 2, 6, 7, 8, 3, 10, 5, 9, null, null FROM dual UNION ALL SELECT 4, '최XX' , 3, 5, 1, 2, 9, 8, 14, 15, 10, null FROM dual UNION ALL SELECT 5, '이XX' , 13, 15, 14, 2, 9, 8, 6, 4, 2, 1 FROM dual ) SELECT id, nm , LISTAGG(no, ',') WITHIN GROUP(ORDER BY seq) x FROM t UNPIVOT (seq FOR no IN ( c1 AS 1 , c2 AS 2 , c3 AS 3 , c4 AS 4 , c5 AS 5 , c6 AS 6 , c7 AS 7 , c8 AS 8 , c9 AS 9 , c10 AS 10 ) ) GROUP BY id, nm ;
To. 케빈재브라위너
1. 서브쿼리를 select 절에 쓰면 무조건 1줄짜리 '단일건 조회'
- 네. 맞습니다. 1줄 1개 항목 조회되는 (스칼라서브쿼리) 입니다.
2. from 절에 쓰면 join 의 개념이니까 그냥 일반테이블 조인한다생각하면 되나요?
- 일반 테이블처럼 생각하면 됩니다. 중간집합이라고 보시면 됩니다.
- 다만, 조인의 개념은 아니죠. 조인 없이 단일 테이블 조회도 가능하니까요.
- From 절의 서브쿼리를 (인라인뷰)라고 합니다.
3. 만드시는 쿼리보면 거의다 서브쿼리를 이용하고계셔서?
- 글쎄요? 제가 거의 다 서브쿼리를 사용한다구요? 그럴리가요?
- 위 댓글 쿼리만 봐도 서브쿼리를 사용하지 않았습니다.
- 저는 어떻게든 쿼리를 간략화 하려고 노력합니다. 그러려면 서브쿼리가 그만큼 적어야 하죠.
4. 어떻게 서브쿼리를 적재적소에 쓰시는지 약간의 팁이 있을까요
- 적재적소는 서브쿼에만 국한된 얘기는 아닙니다. 모든 기능들에 적용해야 하는 말이네요.
- 각 기능들의 특징을 정확하게 알아야 적재적소에 사용 할 수 있습니다.
- 요리와 마찬가지 인 듯 합니다.
- 똑같은 재료가 주어진다고 해도 각 재료의 특성을 정확히 알고 요리하는 고수와
- 레시피만 보고 따라하는 초보 요리사의 음식의 퀄리티는 차이가 나기 마련이죠.
mysql 입니다. ^^
저는 프로시져로 만들어서 랭크를 주긴 했었는데 두 개 비교해 봐야 겠네요^^
CREATE DEFINER=`root`@`%` PROCEDURE `test1`()
BEGIN
DECLARE v_name varchar(10);
DECLARE done1 BOOLEAN DEFAULT FALSE;
DECLARE cursor1 CURSOR FOR select name_a from temp_josa;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done1 = TRUE;
OPEN cursor1;
GET_T1: LOOP
FETCH cursor1 INTO v_name;
IF done1 THEN
LEAVE GET_T1;
END IF;
insert into temp_tot_josa
select
k.gubun,
k.first_sp
from
(
select
'first' as gubun,
first_sp,
rank() over(order by first_sp asc) as ranking
from
temp_josa
where
name_a = v_name
union all
select
'second' as gubun,
second_sp,
rank() over(order by second_sp asc) as ranking
from
temp_josa
where
name_a = v_name
union all
select
'third' as gubun,
third_sp,
rank() over(order by third_sp asc) as ranking
from
temp_josa
where
name_a = v_name
union all
select
'fourth' as gubun,
fourth_sp,
rank() over(order by fourth_sp asc) as ranking
from
temp_josa
where
name_a = v_name
union all
select
'fifth' as gubun,
fifth_sp,
rank() over(order by fifth_sp asc) as ranking
from
temp_josa
where
name_a = v_name
union all
select
'sixth' as gubun,
sixth_sp,
rank() over(order by sixth_sp asc) as ranking
from
temp_josa
where
name_a = v_name
union all
select
'sev_sp' as gubun,
sev_sp,
rank() over(order by sev_sp asc) as ranking
from
temp_josa
where
name_a = v_name
union all
select
'eight_sp' as gubun,
eight_sp,
rank() over(order by eight_sp asc) as ranking
from
temp_josa
where
name_a = v_name
union all
select
'nine_sp' as gubun,
nine_sp,
rank() over(order by nine_sp asc) as ranking
from
temp_josa
where
name_a = v_name
union all
select
'ten_sp' as gubun,
ten_sp,
rank() over(order by ten_sp asc) as ranking
from
temp_josa
where
name_a = v_name
) k
order by k.first_sp;
commit;
END LOOP GET_T1;
CLOSE cursor1;
SET done1= FALSE;
END
-- MySQL -- WITH temp_josa ( name_a , first_sp, second_sp, third_sp, fourth_sp, fifth_sp , sixth_sp, sev_sp, eight_sp, nine_sp, ten_sp ) AS ( SELECT '김길동', 3, 4, 6, 8, 9, 5, 2, 1, 11, 14 UNION ALL SELECT '김XX' , 13, 11, 3, 7, 6, 5, 2, null, null, null UNION ALL SELECT '박XX' , 2, 6, 7, 8, 3, 10, 5, 9, null, null UNION ALL SELECT '최XX' , 3, 5, 1, 2, 9, 8, 14, 15, 10, null UNION ALL SELECT '이XX' , 13, 15, 14, 2, 9, 8, 6, 4, 2, 1 ) SELECT * FROM (SELECT a.name_a , b.gubun , CASE b.gubun WHEN 'first' THEN a.first_sp WHEN 'second' THEN a.second_sp WHEN 'third' THEN a.third_sp WHEN 'fourth' THEN a.fourth_sp WHEN 'fifth' THEN a.fifth_sp WHEN 'sixth' THEN a.sixth_sp WHEN 'seventh' THEN a.sev_sp WHEN 'eighth' THEN a.eight_sp WHEN 'nineth' THEN a.nine_sp WHEN 'tenth' THEN a.ten_sp END sp FROM temp_josa a , (SELECT 'first' gubun UNION ALL SELECT 'second' UNION ALL SELECT 'third' UNION ALL SELECT 'fourth' UNION ALL SELECT 'fifth' UNION ALL SELECT 'sixth' UNION ALL SELECT 'seventh' UNION ALL SELECT 'eighth' UNION ALL SELECT 'nineth' UNION ALL SELECT 'tenth' ) b ) c WHERE sp IS NOT NULL ORDER BY name_a, sp ;
- 저는 어떻게든 쿼리를 간략화 하려고 노력합니다. 그러려면 서브쿼리가 그만큼 적어야 하죠.
이말을 명심하겠습니다. 개발자로서 올해 3월에 입사했는데 실질적으로 쿼리문 작성을 하긴하되, 여기 게시판에 질문올라오는 수준이 아닌 그보다 한참 밑에 수준의 쿼리문을 개발하는 초보 개발자입니다.
처음에는 그냥 구글링해서 찾아서 되는대로 이거저거 해보다가 결과만 맞으면 그쿼리를 사용했었는데
반복적으로 쿼리를 하다보니 이제 쿼리문 작성시에 F9를 눌러서나오는 조회결과가 미리 어느정도 머릿속에 그려져서 짜기전에 먼저 계획적으로 ' 뭐를 셀렉트해서 어떤거랑 조인해서 on절에 뭘 기술하면 내가원하는 어떠한 형태의 결과가 나오겠다 ' 라는 생각을 저도 모르게 하게되더라고요.. (with, unpivot ,partition 같이 어려운 기술없이 그냥 select from join 으로만 짜는쿼리)
그래서 자신감이 좀 붙었는데...
서브쿼리를 만나고나서는 헷갈려서질문드렸었습니다. 덕분에 어떤마음자세로 쿼리를 접해야 할지 조금더 기준이 잡히게됬습니다. 더 공부해보고 조금더 수준이 올라가면 게시판에 질문도 해보겠습니다 감사합니다.
SELECT gubun , COUNT(*) cnt FROM (SELECT GROUP_CONCAT(gubun ORDER BY sp) gubun FROM (SELECT a.name_a , b.gubun , CASE b.gubun WHEN '01' THEN a.first_sp WHEN '02' THEN a.second_sp WHEN '03' THEN a.third_sp WHEN '04' THEN a.fourth_sp WHEN '05' THEN a.fifth_sp WHEN '06' THEN a.sixth_sp WHEN '07' THEN a.sev_sp WHEN '08' THEN a.eight_sp WHEN '09' THEN a.nine_sp WHEN '10' THEN a.ten_sp END sp FROM temp_josa a , (SELECT '01' gubun UNION ALL SELECT '02' UNION ALL SELECT '03' UNION ALL SELECT '04' UNION ALL SELECT '05' UNION ALL SELECT '06' UNION ALL SELECT '07' UNION ALL SELECT '08' UNION ALL SELECT '09' UNION ALL SELECT '10' ) b ) c WHERE sp IS NOT NULL GROUP BY name_a ) d GROUP BY gubun ORDER BY cnt DESC LIMIT 10 ;