Верх 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'
Ответы
Ответ 1
Используйте OUTER APPLY вместо 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';
В отличие от JOIN, APPLY позволяет ссылаться на u.id внутри внутреннего запроса.
Ответ 2
Ключом к отлаживанию подобных ситуаций является запуск подзапроса/встроенного представления на своем "собственном", чтобы увидеть, что такое результат:
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
, чтобы проверить записи для любого пользователя в системе.
Ответ 3
Поскольку TOP 1
из упорядоченного подзапроса не имеет profile_id = 'u162231993'
Удалите where u.id = 'u162231993'
и затем просмотрите результаты.
Запустите дополнительный запрос отдельно, чтобы понять, что происходит.
Ответ 4
Дамир прав,
Ваш подзапрос должен гарантировать, что dps_user.id равно um.profile_id, иначе он будет захватывать верхнюю строку, которая может, но, вероятно, не равна вашему идентификатору 'u162231993'
Ваш запрос должен выглядеть следующим образом:
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'