Stephen Horvath
Stephen Horvath

Reputation: 5588

How do I exclude results if ANY associated row from a join table has NULL for a specific column?

I want to select all of the unique Users where coach is true and available is true but if there are ANY Sessions for that user where call_ends_at is null I don't want to include that user.

call_ends_at can be NULL or have any number of various dates.

Users

id:integer
name:string
coach: boolean
available: boolean

Sessions

id:integer
coach_id: integer
call_ends_at:datetime

Here's what I tried:

SELECT DISTINCT "users".* FROM "users" 
INNER JOIN "sessions" ON "sessions"."coach_id" = "users"."id" 
WHERE "users"."coach" = true 
    AND "users"."available" = true 
    AND ("sessions"."call_ends_at" IS NOT NULL)

But this will still include users if there are sessions with non-null call_ends_at columns.

Upvotes: 0

Views: 36

Answers (3)

wildplasser
wildplasser

Reputation: 44250

  -- I want to select all of the unique Users where coach is true and available is true
SELECT *
FROM users u
WHERE u.coach = true AND u.available = true
    -- but if there are ANY Sessions for that user where call_ends_at is null
    -- I don't want to include that user.
AND NOT EXISTS (
    SELECT *
    FROM sessions s
    WHERE s.coach_id = u.id
    AND s.call_ends_at IS NULL
    ) ;

Upvotes: 1

dnoeth
dnoeth

Reputation: 60472

This is possible with a single EXISTS:

SELECT u.*
FROM "users" u
WHERE u."coach" = true AND u."available" = true 
AND EXISTS
 (
   SELECT s."coach_id"
   FROM "sessions" s
   WHERE s."coach_id" = u."id"
   HAVING COUNT(*) = COUNT("call_ends_at") -- no NULLs
 )

Depending on your actual data & indexes Gordon's answer might be more efficient.

Upvotes: 1

Gordon Linoff
Gordon Linoff

Reputation: 1270081

I think you can do what you want using EXISTS and NOT EXISTS:

SELECT u.*
FROM "users" u
WHERE u."coach" = true AND u."available" = true AND
      EXISTS (SELECT 1
              FROM "sessions" s
              WHERE s."coach_id" = u."id" 
             )
      NOT EXISTS (SELECT 1
                  FROM "sessions" s
                  WHERE s."coach_id" = u."id" AND
                        s."call_ends_at" IS NULL
                 );

Upvotes: 1

Related Questions