简体   繁体   中英

Left outer join SQL Server

I'm confused as to why this is not working, I've used this type of syntax several times but this one as got me pulling my hair out.

I have two tables;

tableA

regId name    regStatus
1     George  1
2     Jenny   1
3     Penny   1
4     James   1
5     Preston 1
6     Jamie   0

TableB

activeRegId passiveRegID Status
1            2           1
1            3           1
1            4           0
6            1           1

What I'm trying to do is return all rows from tableA excluding those where (tableA.regstatus = 0) and (tableB.status = 1 for a user regid = 1) .

I want to avoid having to use NOT IN (select ...) .

My query so far:

    select top 10 
        tA.regId, tA.name
    from 
        tableA tA 
    left OUTER JOIN 
        tableB tB ON tB.activeRegId = tA.regid AND tB.passiveRegID <> 1 
                     AND tB.status <> 1 AND tB.passiveRegID IS NULL
    where 
        tA.regStatus = 1
        and tA.regid <> 1

What I'm expecting back should be as follows however, I'm getting all the users in tableA except for Jamie.

regId name
4     James
5     Preston

I think you need to move some of the predicates out of the ON clause of the LEFT OUTER JOIN, and instead have them as predicates in the WHERE clause.

Based on the data you provided, I can't be sure exactly what the predicates should be, however any predicates you include in the ON clause of a LEFT OUTER JOIN only serve to exclude rows from Table B, not Table A.

With a LEFT OUTER JOIN, you will still get all records of Table A unless they are excluded by predicates in the WHERE clause.

EDIT Based on comments, I think this would work, where 'loggedInUserId' is the regId from Table A of the logged in user:

SELECT top 10
   tA.regId,
   tA.name
FROM tableA tA1
JOIN tableA tA2
ON (tA1.regId <> tA2.regId
    AND tA2.regStatus <> 0)
LEFT OUTER JOIN tableB tB
ON (tA1.regId = tB.activeRegId
    AND tA2.regId = tB.passiveRegID
    AND tB.Status <> 0)
WHERE tA1.regId = 'loggedInUserId'
AND tB.activeRegId IS NULL

To also exclude those who have blocked the logged in user:

SELECT top 10
   tA.regId,
   tA.name
FROM tableA tA1
JOIN tableA tA2
ON (tA1.regId <> tA2.regId
    AND tA2.regStatus <> 0)
LEFT OUTER JOIN tableB tB
ON (
    --finding blocked users
    (tA1.regId = tB.activeRegId
     AND tA2.regId = tB.passiveRegID
     AND tB.Status <> 0)
    OR
    --finding blocking users
    (tA2.regId = tB.activeRegId
     AND tA1.regId = tB.passiveRegId
     AND tB.Status <> 0)
    )
WHERE tA1.regId = 'loggedInUserId'
AND tB.activeRegId IS NULL

If you don't want to use NOT IN , what about using EXCEPT to exclude those you don't want?

SELECT regId
  FROM tableA
EXCEPT
SELECT tA.regId
  FROM tableA tA
  JOIN tableB tB ON (tB.activeRegId = tA.regid AND tB.passiveRegID = 1 AND tB.status = 1)
  WHERE tA.regStatus = 0

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM