Reason for NOT IN behaviour
SELECT * FROM runners WHERE id NOT IN (SELECT winner_id FROM races);


Is something like this (actual values from races):

SELECT * FROM runners WHERE
id &lt;&gt; 2 and
id &lt;&gt; 3 and
id &lt;&gt; null;


id &lt;&gt; null is unknown by definition, so the whole where clause evaluates to either false (for ids: 2, 3) or unknown (for ids: 1, 4, 5) because of the and operators, thus no result returned.

If you want to run the query disregarding the nulls in races, you can use:

SELECT * FROM runners 
WHERE id NOT IN 
      (SELECT winner_id FROM races WHERE winner_id IS NOT NULL);