Zdecydowałbym się na coś takiego:
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
Przenoszenie AND
do klauzuli join sprawia, że łączenie się powiedzie lub zakończy się niepowodzeniem, co ma kluczowe znaczenie dla zachowania wynikowych wierszy tam, gdzie nie ma pasującego wiersza w „prawej” tabeli.
Gdyby znajdował się w WHERE
, porównania z wartością NULL (gdzie nie ma kodu_kampanii) zakończą się niepowodzeniem i zostaną usunięte z wyników.