2012-01-23 4 views
8

멤버 레코드 목록을 표시하려고하는데 필요한 항목을 표시하는 데 사용하는 테이블이 몇 개 있습니다.MySQL 하위 쿼리 - LEFT JOIN의 첫 번째 레코드 만 찾습니다.

그건 쉬운 부분입니다. 도움이 필요한 부분은 각 회원 기록에 많은 기록이있는 테이블입니다. 로그인 내역

로그인 기록 테이블에있는 각 회원 레코드의 첫 번째 행만 표시하려고합니다. 또는 플립 플립하고 로그인 기록 테이블의 마지막 레코드를 표시 할 수도 있습니다.

여기에 지금까지있어 무엇 :

SELECT m.memberid, m.membername, m.gender, mp.phone 
FROM tbl_members m, 
    tbl_members_phones mp, 
    tbl_members_addresses ma 
WHERE m.defaultphoneid = mp.phoneid 
AND m.defaultaddressid = ma.addressid 

그래서 예상 무엇을 반환합니다.

두 개의 열 tbl_members_login_history에서 반환 된 결과에 다음과 같이 추가하고 싶습니다. mh. loggedtime, mh. ipaddy

왼쪽 중복을 반환 가입으로 나는 tbl_members_login_history를 추가 알고, 그래서 나는 tbl_members_login_history에 존재하는 memberid을 위해 단지 1 레코드를 반환하기 위해, 여기에 하위 쿼리 필요성이 있어야한다 생각하고 있어요.

걱정되는 점은 내역 테이블에 레코드가없는 경우 해당 멤버 정보를 표시하려고하지만 내역 열은 NULL로 두는 것입니다.

하위 쿼리 문제일까요? 그렇다면 LIMIT 유형을 어떻게 추가할까요?

+0

호기심, 회원은 전화와 주소를 필요합니까? 그렇지 않은 경우, 귀하의 질문 중 하나가 쓰여진 방식대로 누락 된 경우 귀하의 질의가 다른 회원 정보를 반환 할 것이라고 생각하지 않습니다. – Sam

+0

이 경우 예. 그러나 당신 말이 맞습니다. 회원은 기존 기록이 없으면 결과에 반환되지 않습니다. – coffeemonitor

답변

20

이것은 스택 오버플로에서 자주 묻는 greatest-n-per-group 문제입니다. 여기

내가 시나리오에서 그것을 해결할 방법은 다음과 같습니다

입니다
SELECT m.memberid, m.membername, m.gender, mp.phone, mh.loggedtime, mh.ipaddy 
FROM tbl_members m 
INNER JOIN tbl_members_phones mp ON m.defaultphoneid = mp.phoneid 
INNER JOIN tbl_members_addresses ma ON m.defaultaddressid = ma.addressid 
LEFT OUTER JOIN tbl_members_login_history mh ON m.memberid = mh.memberid 
LEFT OUTER JOIN tbl_members_login_history mh2 ON m.memberid = mh2.memberid 
    AND mh.pk < mh2.pk 
WHERE mh2.pk IS NULL; 

, 우리는 주어진 MEMBERID에 대한 tbl_member_login_history에서 가장 최근의 행 수 mh를 원한다. 따라서 더 최근의 행 mh2을 검색합니다. mh 행보다 최신 행이없는 경우 mh2.*은 NULL이되므로 mh이 가장 최근의 것이어야합니다.

이 테이블에는 증가하는 값을 포함하는 기본 키 열이 있다고 가정합니다. 이 예에서는 열 이름이 pk이라고 가정합니다.

에 대해 LEFT OUTER JOIN을 사용하십시오. 로그인 기록 테이블에 대한 참조는 일치하는 행이없는 경우에도 m 행이보고된다는 것을 의미합니다.

+0

방금 ​​솔루션을 시도하고 'GROUP BY'와'MAX (...) '를 사용하여 하위 쿼리를 포함하고'ON date = maxdate '에 참여하는 쿼리와 비교했습니다.하위 쿼리 솔루션은 0.01 초 (물론 동일한 결과 테이블)를 사용하는 반면,'< '연산자를 사용하는 솔루션은 2 초 (!)를 사용했습니다. 쿼리의'EXPLAIN'은 서브 쿼리가있는 것보다 훨씬 낫습니다. 왜 이렇게 큰 성능 차이가 나는지 모르겠지만,'<'는 거대한 중간 결과를 산출하기 때문입니다. – steffen

+0

@steffen : 네,이 질문에 답한 이후로 저는 다른 많은 경우를 보았습니다. 위와 같은 해결책이나 설명하는 솔루션이 얼마나 많은 그룹과 얼마나 많은 그룹에 따라 빠를 수 있다고 결론지었습니다. 그룹당 데이터 행의 수입니다. 따라서 두 가지 방법을 모두 데이터로 테스트 한 다음 결정하는 것이 가장 좋습니다. –

+0

참. 저를 혼란스럽게 만들었던 것은 엄청난 성능 차이였습니다. 나는 당신의 해결책을 여기 몇 번 발견했다. 그리고'EXPLAIN' 출력이 멋져서 쿼리가 매우 빨라질 것으로 예상했습니다. 그러나 대신 그것은 훨씬 더 느렸다. 기묘한. – steffen

0

LEFT OUTER JOIN (SELECT member_id, MAX(LAST_LOGIN_DATE) from tbl_members_login_history) Last_Login ON Last_Login.memberid = m.memberid 

PS처럼 추가 할 수 있습니다. LAST_LOGIN_DATE 의사 열입니다, 당신은 restictive 열을 시도 할 수 있습니다

관련 문제