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

LEFT JOIN の代わりに OUTER APPLY を使用します。

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'

idこれにより、句の値を変更してwhere、システム内の任意のユーザーのレコードを確認できます。

于 2010-01-09T16:38:34.943 に答える
2

順序付けられたサブクエリからのには削除TOP 1がないため、結果を確認してください。profile_id = 'u162231993'where u.id = 'u162231993'

サブクエリを個別に実行して、何が起こっているのかを理解してください。

于 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 に答える