109

鉴于下面的查询,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

4 回答 4

231

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

于 2010-01-09T18:19:49.747 回答
4

调试此类情况的关键是自行运行子查询/内联视图以查看输出是什么:

  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.idu162231993mbgnull

您已经使用 将自己编码到一个角落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'

这样,您可以更改子句中的idwhere以检查系统中任何用户的记录。

于 2010-01-09T16:38:34.943 回答
2

因为TOP 1从有序子查询中没有profile_id = 'u162231993' Remove where u.id = 'u162231993'and see results 然后。

单独运行子查询以了解发生了什么。

于 2010-01-09T14:54:34.670 回答
1

达米尔是对的,

您的子查询需要确保 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'
于 2010-01-09T15:07:44.470 回答