Eu optaria por algo como:
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
Movendo o
AND
à cláusula de junção faz com que a junção seja bem-sucedida ou falhe, mantendo crucialmente as linhas resultantes onde não há linha correspondente na tabela 'direita'. Se estivesse no
WHERE
, as comparações com NULL (onde não há código_campanha) falhariam e seriam eliminadas dos resultados.