Топ 1 с левым соединением
учитывая запрос ниже, в dps_markers может быть несколько строк с одним и тем же ключом маркера, но мы хотим присоединиться только к первому. Если я возьму этот запрос и удалю верхний 1 и закажу, я получу значение для 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'
4 ответа:
используйте внешний применить вместо левого соединения:
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';
в отличие от присоединения, применять позволяет ссылаться на U.идентификатор внутри внутренний запрос.
ключом к отладке подобных ситуаций является запуск подзапроса / встроенного представления самостоятельно, чтобы увидеть, что такое вывод:
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.идентификатор равен единой системы обмена сообщениями.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'