前1名左连接

时间:2010-01-09 14:43:25

标签: sql-server outer-join

根据下面的查询,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'

4 个答案:

答案 0 :(得分:169)

使用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。

答案 1 :(得分: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的{​​{1}}值不匹配,这可以解释为什么任何u162231993引用都会返回{{ 1}}(感谢左连接;如果它是内连接,你将得不到任何东西。)

您已使用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' 值,以检查系统中任何用户的记录。

答案 2 :(得分:1)

因为有序子查询中的TOP 1没有profile_id = 'u162231993' 删除where u.id = 'u162231993'然后查看结果。

分别运行子查询以了解发生了什么。

答案 3 :(得分:0)

达米尔是对的,

您的子查询需要确保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'