[sql-server] 왼쪽 조인이있는 상위 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'
한 후 결과를 참조하십시오.
무슨 일이 일어나고 있는지 이해하기 위해 하위 쿼리를 별도로 실행하십시오.
답변
Damir가 맞습니다.
하위 쿼리는 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'