by 쿼리냠냠 [SQL Query] [2020.05.28 15:40:38]
구루비 회원님들 안녕하세요.
쿼리를 짜다가 궁금한게 있어 문의드립니다.
테이블 부터 알려드리겠습니다.
테이블명 : 상품테이블
id | name | optionStatus | optionId | price |
1 | 바나나 | true | A | 2000 |
2 | 수박 | true | A | 1000 |
3 | 사과 | false | null | 10 |
4 | 참치 | false | A | 10 |
5 | 고등어 | false | B | 10 |
6 | 치킨 | true | B | 100 |
7 | 피자 | true | B | 50 |
8 | 햄버거 | true | B | 200 |
9 | 족발 | false | null | 10 |
[질문]
1. 여기서 SELECT * FROM 상품테이블을 하면 위와같이 나옵니다.
2. 제가 원하는 결과값은 다음과 같습니다.
- optionStatus값이 true 면서(AND) optionId가 같으면 1개만 표시
=> (true인상태에서) optionId가 여러개라면 1개만표시
- optionStatus값이 false라면 optionId값과 상관없이 모두 출력
id | name | optionStatus | optionId |
1 | 바나나 | true | A |
3 | 사과 | false | null |
4 | 참치 | false | A |
5 | 고등어 | false | B |
6 | 치킨 | true | B |
9 | 족발 | false | null |
==>
GROUP BY 절도써보다가 잘안되서 질문드립니다.
도와주세요!
*추가*
위의 조건을 기준으로 최저가로 데이터를 가져오기
id | name | optionStatus | optionId | price |
2 | 수박 | true | A | 1000 |
3 | 사과 | false | null | 10 |
4 | 참치 | false | A | 10 |
5 | 고등어 | false | B | 10 |
7 | 피자 | true | B | 50 |
9 | 족발 | false | null | 10 |
감사합니다. 좋은하루 보내세요!
id는 row 번호인가요? 일단 id를 그대로 했습니다..
with t as ( select 1 id, '바나나' name, 'true' optionStatus, 'A' optionId from dual union all select 2, '수박' , 'true' , 'A' from dual union all select 3, '사과' , 'false', null from dual union all select 4, '참치' , 'false', 'A' from dual union all select 5, '고등어', 'false', 'B' from dual union all select 6, '치킨' , 'true' , 'B' from dual union all select 7, '피자' , 'true' , 'B' from dual union all select 8, '햄버거', 'true' , 'B' from dual union all select 9, '족발' , 'false', null from dual ) select id, name, optionStatus, optionId from (select id, name, optionStatus, optionId, row_number() over (partition by optionStatus,optionId order by id) rn from t) t1 where (t1.optionStatus = 'true' and t1.rn = 1 ) or (t1.optionStatus = 'false') order by id ;
WITH t AS ( SELECT 1 id, '바나나' name, 'true' optionStatus, 'A' optionId UNION ALL SELECT 2, '수박', 'true', 'A' UNION ALL SELECT 3, '사과', 'false', null UNION ALL SELECT 4, '참치', 'false', 'A' UNION ALL SELECT 5, '고등어', 'false', 'B' UNION ALL SELECT 6, '치킨', 'true', 'B' UNION ALL SELECT 7, '피자', 'true', 'B' UNION ALL SELECT 8, '햄버거', 'true', 'B' UNION ALL SELECT 9, '족발', 'false', null ) SELECT * FROM (SELECT id, name, optionStatus, optionId , RANK() OVER(PARTITION BY optionStatus, optionId ORDER BY CASE optionStatus WHEN 'true' THEN id END) rk FROM t ) a WHERE rk = 1 ORDER BY id ;
안녕하세요. 답변감사합니다ㅠ
mysql버전이 낮아 사용하지 못하는 문법들이 있어 생략하고 실행해봤었습니다. (WITH, OVER ... )
단순히 순위를 매기는 건줄 알고요.( mysql 5.6버전대입니다. )
알려주신 쿼리문을 가지고 다른 방법으로 활용해보고 이것저것 시도해보고있습니다ㅠ
현재 해보려고하는건
1. (1번)optionStatus값이 true 면서(AND) optionId가 같으면 1개만 추출하는 데이터를 조회하고
2. (1번)에 데이터를 서브쿼리에 넣어서 값을 가져와 볼까 생각하고 있어요.
id | name | optionStatus | optionId | subqueryResult |
1 | 바나나 | true | A | true |
2 | 수박 | true | A | |
3 | 사과 | false | null | |
4 | 참치 | false | A | |
5 | 고등어 | false | B | true |
6 | 치킨 | true | B | |
7 | 피자 | true | B | |
8 | 햄버거 | true | B | |
9 | 족발 | false | null |
마농님 안녕하세요.
제가 질문했던 글에서 price라는 컬럼을 추가하였고,
기존에 알려주신 쿼리를 응용해보려하였지만 잘되지않아 문의드립니다.
( 기존 쿼리를 a.id > b.id라서 이거 대신 다른 조건문을 써서 가져와바야겠다 했는데 잘 되지 않더라구요 ㅠ...)
감사합니다. 좋은 하루보내세요!
조건은 다음과 같습니다.
1.(기존과동일) optionStatus값이 true 면서(AND) optionId가 같으면 1개만 표시
=> (true인상태에서) optionId가 여러개라면 1개만표시
(신규) => 1개만 표시하되, 최저가인 데이터를 가져오기.
2.(기존과동일) optionStatus값이 false라면 optionId값과 상관없이 모두 출력
결과값
id | name | optionStatus | optionId | price |
2 | 수박 | true | A | 1000 |
3 | 사과 | false | null | 10 |
4 | 참치 | false | A | 10 |
5 | 고등어 | false | B | 10 |
7 | 피자 | true | B | 50 |
9 | 족발 | false | null | 10 |
간단하게 생각하면 다음과 같이 변경하면 됩니다.
- 변경전 : AND a.id > b.id
- 변경후 : AND a.price > b.price
다만, id 의 경우엔 유일값이지만, price 는 중복이 가능한 값이므로 단순하게 변경해선 안됩니다.
중복 값에 대한 표현 방법을 정해야 합니다.
중복값이 없다거나 중복이 있다면 모두 보여준다라고 하면? AND a.price > b.price 하면 됩니다.
중복이 있을 경우 그중 하나를 선택해서 보여줘야 한다면?
선택 기준을 제시해야 합니다. (예 : ID 가 작은거 우선)
최저가 중에 ID 가 작은 거 우선이라면 다음과 같이.
AND ( (a.price > b.price) OR (a.price = b.price AND a.id > b.id) )
늘 친절한 답변 감사드립니다.
최저가(a.price>b.price)를 했을때 중복값이 발생가능성이 있으니 기준값을 조건문에 추가를 해야한다는 말을 이해했습니다.
(id와 달리 price는 유니크값이 아니니!)
다만 알려주신 쿼리문으로는 원하는 결과값을 가져올 수가 없어 고민하고있었습니다.
쿼리를 돌리면 다음과 같습니다.
SELECT a.* ,b.*
FROM t1 a
LEFT OUTER JOIN t1 b
ON a.optionStatus = 'true'
AND a.optionStatus = b.optionStatus
AND a.optionId = b.optionId
AND ( (a.price > b.price) OR (a.price = b.price AND a.id > b.id) )
order by a.id asc;
#WHERE b.id IS NULL;
==> 일단 b.id is null은 주석처리를 하였습니다.
*결과데이터*
a.id |
a.name |
a.optionStatus |
a.optionId |
a.price |
b.id |
b.name |
b.optionStatus |
b.optionId |
b.price |
1 |
바나나 |
TRUE |
A |
3000 |
2 |
수박 |
TRUE |
A |
2000 |
2 |
수박 |
TRUE |
A |
2000 |
NULL |
NULL |
NULL |
NULL |
NULL |
3 |
사과 |
FALSE |
NULL |
1000 |
NULL |
NULL |
NULL |
NULL |
NULL |
4 |
참치 |
FALSE |
A |
1000 |
NULL |
NULL |
NULL |
NULL |
NULL |
5 |
고등어 |
FALSE |
B |
20 |
NULL |
NULL |
NULL |
NULL |
NULL |
6 |
치킨 |
TRUE |
B |
100 |
NULL |
NULL |
NULL |
NULL |
NULL |
7 |
피자 |
TRUE |
B |
50 |
8 |
햄버거 |
TRUE |
B |
200 |
7 |
피자 |
TRUE |
B |
50 |
6 |
치킨 |
TRUE |
B |
100 |
8 |
햄버거 |
TRUE |
B |
200 |
6 |
치킨 |
TRUE |
B |
100 |
9 |
족발 |
FALSE |
NULL |
1000 |
NULL |
NULL |
NULL |
NULL |
NULL |
1. id값이 [6/7/8]의 경우 option값이 true면서 optionId가 동일하기 때문에 1개만 가져와합니다.
2. 기존 쿼리는 WHERE b.id IS NULL;이기 때문에 최저가인 '피자'가 빠지게 됩니다.
==> a,b 비교하는 데이터자체를 변경한 후 말씀해주신 중복값을 제거해야되는데
비교대상의 데이터자체를 변경하는데 어려움이 있습니다ㅠ