Étant donné la requête ci-dessous, il pourrait y avoir plusieurs lignes dans dps_markers avec la même clé de marqueur, mais nous souhaitons uniquement nous joindre à la première. Si je prends cette requête et supprime le top 1 et ORDER BY, j'obtiens une valeur pour mbg.marker_value mais je l'exécute telle quelle, elle renvoie toujours 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'
Utilisez OUTER APPLY au lieu de LEFT JOIN:
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';
A la différence de JOIN, APPLY vous permet de référencer le u.id dans la requête interne.
La clé de ce type de débogage consiste à exécuter la vue sous-requête/en ligne seule pour voir quelle est la sortie:
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
En exécutant cela, vous verriez que le profile_id
La valeur ne correspond pas à la u.id
valeur de u162231993
, ce qui expliquerait pourquoi toutes les références mbg
renvoient null
(grâce à la jointure gauche; vous n’obtenez rien si c’était une jointure interne).
Vous vous êtes codé dans un coin en utilisant TOP
, car vous devez maintenant modifier la requête si vous souhaitez l'exécuter pour d'autres utilisateurs. Une meilleure approche serait:
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'
Avec cela, vous pouvez modifier la valeur id
de la clause where
pour vérifier les enregistrements de tout utilisateur du système.
Parce que le TOP 1
de la sous-requête ordonnée n'a pas profile_id = 'u162231993'
Retirer where u.id = 'u162231993'
et voir les résultats alors.
Exécutez la sous-requête séparément pour comprendre ce qui se passe.
Damir a raison,
Votre sous-requête doit vous assurer que dps_user.id est égal à um.profile_id. Sinon, il prendra la ligne du haut qui pourrait, mais ne correspondra probablement pas à votre identifiant "u162231993".
Votre requête devrait ressembler à ceci:
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'