2017-03-07 8 views
0

사용자가 작성한 시음 노트와 다른 사용자가 각 시음 노트에주는 등급이있는 테이블이 있습니다.mySQL 데려 오기 결과가 없어야합니다.

아직이 같은 외모를 평가하지 않은 다른 사용자가 작성한 모든 메모가 나타납니다 쿼리 :

SELECT tastingNotes.userID, tastingNotes.beerID, tastingNotes.noteID, tastingNotes.note, COALESCE(sum(tasteNoteRate.Score), 0) as count, 
CASE 
WHEN tasteNoteRate.userVoting = 1162 THEN 1 
ELSE 0 
END AS userScored 
FROM tastingNotes 
left join tasteNoteRate on tastingNotes.noteID = tasteNoteRate.noteID 
WHERE tastingNotes.userID != 1162 
Group BY tastingNotes.noteID 
HAVING userScored < 1 
ORDER BY count, userScored 

사용자 1162이 보여 tasteNoteRate 테이블에서 노트 (113)에 대한 메모를 작성했습니다 로까지 : 여전히 .... 위의 쿼리를 실행할 때마다 반환

noteID | userVoting | score 
    113  1162  0 

하지만 내부에

+2

SQL92 준수'GROUP BY'를 읽어 보시기 바랍니다. – Kermit

+0

정확히 무엇을 찾아야합니까? Kermit – Mike

+0

나는이 시도뿐만 아니라 달성하려는 것에 대한 설명을 제시하는 것이 유용 할 수도 있다고 생각합니다. 당신이 예상대로 작동하지 않습니다. 이 특정 접근법은 완전히 잘못 인도 될 수 있으며 수행하려는 작업을 수행하는 더 간단한 방법이 될 수 있습니다. – moreON

답변

0

변경은 가입 할 수 있습니다.

tasteNoteRate 테이블이 tastingNotes에 조인 된 채로 남아 있습니다. 즉, tastingNotes 테이블 전체가 반환되고 tasteNoteRate 테이블의 일치하는 필드에 의해 확장됩니다. tasteNoteRate가 충족되지 않으면 tastingNotes가 일치 필드를 반환하지 않습니다. 내부 조인은 교차를 가져옵니다.

조인의 종류의 많은 설명은 여기를 참조하십시오 :

What's the difference between INNER JOIN, LEFT JOIN, RIGHT JOIN and FULL JOIN?

신속 폭발 사건을 두 테이블 noteID에 인덱스 또는이 쿼리를 생성하고 사용할 수 있는지 확인합니다.

참고 : 사용 사례로 작성한 내용을 토대로 여전히 noteID에 가입하려는 것으로 확신하지는 않습니다. 그것은 그대로, 그것은 모든 사용자에 대한 모든 등급과 결합 모든 메모에 조인 된 테이블을 제공하려고합니다. CASE ... END는 쿼리 최적화 프로그램을 방해하고 전체 스캔 + 결합으로 전환 할 것이라고 생각합니다. 왜 그냥 where ... "and tasteNoteRate.userVoting = 1162"에 다른 절을 추가하지 않으시겠습니까?

이 테이블이 1-1이 아닌 경우 (sum() 및 "group by"으로 표시됨) 현재 쿼리가 폭발적인 문제에 직면하게됩니다. 모든 노트가 10 개의 서로 다른 등급을 가질 수 있고 10 개의 노트가있는 경우 100 개의 후보 결과 행이 있습니다. 1000 및 1000으로 증가하면 메모리가 부족합니다. userID가 투표하지 않은 몇 개의 행을 제거하면 결국 1,000,000+에서 10 개의 행을 제거한 다음 합쳐서 그룹화합니다.

당신이 그것을 할 수있는 다른 방법은 왼쪽을 반대하는 것입니다 가입 :

select ...,sum()... from tasteNoteRate ... left join tastingNotes using (noteID) where userID != xxx group by noteID, 당신은 단지 다른 사용자의 메모 tastingNotes 정보를 얻을 그런 식으로.

어쩌면 도움이 될지도 모르겠지만, 예, SCHEMA 및 특정 사용 사례/예제 데이터가 도움이됩니다.

"등급 등급"의 이러한 종류의 경우, 투표 합계의 요약표를 유지하고 사용자가 이미 투표 한 내용을 추적하는 것이 더 나은 경우가 있습니다. 예 : select 쿼리에서 이들을 합치 지 마십시오. 대신, insert...on duplicate key update (total = total + 1); 적어도 내가 일부 사용자 순위 테이블에서 문제를 처리하는 방법. 그들은 너무나 빠르게 커집니다.

2

MySQL은 당신이보고, 불평하지 않고 오히려 특별한 방법으로 group by를 사용 할 수 있습니다 documentation : ONLY_FULL_GROUP_BY을 사용하지 않으면

, GROUP BY의 표준 SQL 사용에 대한 MySQL의 확장 HAVING, 선택 목록을 허용 조건 또는 ORDER BY 목록을 사용하여 열이 GROUP BY 열에 기능적으로 종속되어 있지 않더라도 비 집합 열을 참조 할 수 있습니다. [...] 이 경우 서버는 각 그룹에서 임의의 값을 자유롭게 선택할 수 있으므로 동일하지 않으면 선택한 값이 불확실합니다. 이는 사용자가 원하는 값이 아닐 수 있습니다..

이 동작은 MySQL 5.7 이전의 기본 동작이었습니다. 이 특정 noteID에 대한 tasteNoteRate에 하나 개 이상의 행이, 그래서 다른 사람이 이미 집계 함수없이 tasteNoteRate.userVoting을 사용한다는 점에 유의 userScored, 투표 한 경우, 기반 될 경우, 의미 귀하의 경우에는

무작위 행 - 잘못된 행.

당신은 집계 사용하여 해당 문제를 해결할 수 : (null 이외로) 비교의 결과가 1 또는 0이기 때문에,

select ..., 
    max(CASE 
    WHEN tasteNoteRate.userVoting = 1162 THEN 1 
    ELSE 0 
    END) AS userScored 
from ... 

또는, 당신은 또한 짧은 버전을 사용할 수 있습니다 :

select ..., 
    coalesce(max(tasteNoteRate.userVoting = 1162),0) AS userScored 
from ... 

는 MySQL을 5.7으로 업그레이드 준비 (및 ONLY_FULL_GROUP_BY를 사용) 할로해야 당신의 select -list에 이미 group by 모든 비 집계 열 : group by tastingNotes.userID, tastingNotes.beerID, tastingNotes.noteID, tastingNotes.note. 이 또한

select tastingNotes.*, 
     coalesce(rates.count, 0) as count, 
     coalesce(rates.userScored,0) as userScored 
from tastingNotes 
left join (
    select tasteNoteRate.noteID, 
     sum(tasteNoteRate.Score) as count, 
     max(tasteNoteRate.userVoting = 1162) as userScored 
    from tasteNoteRate 
    group by tasteNoteRate.noteID 
) rates 
on tastingNotes.noteID = rates.noteID and rates.userScored = 0 
where tastingNotes.userID != 1162 
order by count; 

: 당신이 group bytastingNotes의 모든 열을하지 않아도

(다른 사람의 사이에) 쿼리를 작성하는 다른 방법은 하위 쿼리에 tastingNoteRates의 그룹화를 수행하는 것 on 절의 rates.userScored = 0= 1으로 변경하여 사용자가 투표 한 메모를 가져올 수 있습니다.

+0

도움과 도움에 감사드립니다. 큰 설명! – Mike