source

왼쪽 조인 포함 상위 1위

nicesource 2023. 4. 19. 23:15
반응형

왼쪽 조인 포함 상위 1위

아래 쿼리에서 dps_markers에 동일한 마커 키를 가진 여러 행이 있을 수 있지만 첫 번째 행에 대해서만 참여하려고 합니다.이 쿼리를 사용하여 상위 1과 ORDER BY를 삭제하면 mbg.marker_value 값이 표시되지만 그대로 실행되면 항상 null이 반환됩니다.

SELECT u.id, mbg.marker_value 
FROM dps_user u
LEFT JOIN 
    (SELECT TOP 1 m.marker_value, um.profile_id
     FROM dps_usr_markers um (NOLOCK)
         INNER JOIN dps_markers m (NOLOCK) 
             ON m.marker_id= um.marker_id AND 
                m.marker_key = 'moneyBackGuaranteeLength'
     ORDER BY m.creation_date
    ) MBG ON MBG.profile_id=u.id 
WHERE u.id = 'u162231993'

LEFT JOIN 대신 Outer APPLY:

SELECT u.id, mbg.marker_value 
FROM dps_user u
OUTER APPLY 
    (SELECT TOP 1 m.marker_value, um.profile_id
     FROM dps_usr_markers um (NOLOCK)
         INNER JOIN dps_markers m (NOLOCK) 
             ON m.marker_id= um.marker_id AND 
                m.marker_key = 'moneyBackGuaranteeLength'
     WHERE um.profile_id=u.id 
     ORDER BY m.creation_date
    ) AS MBG
WHERE u.id = 'u162231993';

JOIN과 달리 APPLY를 사용하면 내부 쿼리 내의 u.id을 참조할 수 있습니다.

다음과 같은 상황을 디버깅할 때 중요한 것은 서브쿼리/인라인 뷰를 단독으로 실행하여 출력 결과를 확인하는 것입니다.

  SELECT TOP 1 
         dm.marker_value, 
         dum.profile_id
    FROM DPS_USR_MARKERS dum (NOLOCK)
    JOIN DPS_MARKERS dm (NOLOCK) ON dm.marker_id= dum.marker_id 
                                AND dm.marker_key = 'moneyBackGuaranteeLength'
ORDER BY dm.creation_date

그것을 실행해 보면, 당신은 이 모든 것이profile_id값이 일치하지 않음u.id의 가치u162231993그 이유를 설명해주죠mbg참조가 반환됩니다.null(왼쪽 조인트 덕분에 안쪽 조인트라면 아무것도 얻을 수 없습니다).

당신은 자신을 코너에 몰아넣고TOP다른 사용자에 대해 쿼리를 실행하려면 쿼리를 조정해야 하기 때문입니다.보다 나은 접근법은 다음과 같습니다.

   SELECT u.id, 
          x.marker_value 
     FROM DPS_USER u
LEFT JOIN (SELECT dum.profile_id,
                  dm.marker_value,
                  dm.creation_date
             FROM DPS_USR_MARKERS dum (NOLOCK)
             JOIN DPS_MARKERS dm (NOLOCK) ON dm.marker_id= dum.marker_id 
                                         AND dm.marker_key = 'moneyBackGuaranteeLength'
           ) x ON x.profile_id = u.id
     JOIN (SELECT dum.profile_id,
                  MAX(dm.creation_date) 'max_create_date'
             FROM DPS_USR_MARKERS dum (NOLOCK)
             JOIN DPS_MARKERS dm (NOLOCK) ON dm.marker_id= dum.marker_id 
                                         AND dm.marker_key = 'moneyBackGuaranteeLength'
         GROUP BY dum.profile_id) y ON y.profile_id = x.profile_id
                                   AND y.max_create_date = x.creation_date
    WHERE u.id = 'u162231993'

이 기능을 사용하면,id값어치where시스템 내 모든 사용자의 레코드를 체크하기 위한 구를 지정합니다.

왜냐하면TOP 1명령된 하위 항목에서profile_id = 'u162231993'제거한다.where u.id = 'u162231993'결과를 볼 수 있습니다.

서브쿼리를 개별적으로 실행하여 상황을 파악합니다.

다미르 말이 맞아요

서브쿼리에서는 dps_user.id가 um.profile_id와 동일한지 확인해야 합니다.그렇지 않으면 u162231993의 ID와 동일하지는 않을 수 있지만 맨 위 행이 나타납니다.

쿼리는 다음과 같습니다.

SELECT u.id, mbg.marker_value 
FROM dps_user u
LEFT JOIN 
    (SELECT TOP 1 m.marker_value, um.profile_id
     FROM dps_usr_markers um (NOLOCK)
         INNER JOIN dps_markers m (NOLOCK) 
             ON m.marker_id= um.marker_id AND 
                m.marker_key = 'moneyBackGuaranteeLength'
     WHERE u.id = um.profile_id
     ORDER BY m.creation_date
    ) MBG ON MBG.profile_id=u.id 
WHERE u.id = 'u162231993'

언급URL : https://stackoverflow.com/questions/2033699/top-1-with-a-left-join

반응형