Io opterei per qualcosa come:
SELECT
c.id AS campaign_id,
COUNT(cc.id) AS code_count
FROM
campaigns c
LEFT JOIN campaign_codes cc on cc.campaign_id = c.id
AND cc.status = 0 -- Having this clause in the WHERE, effectively makes this an INNER JOIN
WHERE c.partner_id = 4
GROUP BY c.id
Spostando il AND
alla clausola join fa sì che il join abbia esito positivo o negativo, mantenendo in modo cruciale le righe risultanti in cui non ci sono righe corrispondenti nella tabella "di destra".
Se fosse nel WHERE
, i confronti con NULL (dove non c'è codice_campagna) fallirebbero e verrebbero eliminati dai risultati.