Musisz umieścić czek użytkownika w przyłączeniu, a nie w warunku gdzie:
SELECT c.course_id,l.topic,l.id,l.vid_duration,p.*
FROM courses c
LEFT JOIN lessons l ON l.course_id=c.course_id
LEFT JOIN progress p ON l.id = p.lesson_id and p.user_id = :userid
WHERE c.slug = :course
Powodem tego jest to, że JOINS używa „lewego sprzężenia” (które jest niejawnie sprzężeniem zewnętrznym). Ten typ sprzężenia oznacza, że jeśli warunek działa, zwróć wszystkie dane kolumny dla tej tabeli dla tego wiersza.. jeśli całość warunek nie działa, zwróci wszystkie dane dla tabel wymienionych wcześniej, ale dla tabeli wymienionej w wierszu zwróci NULL dla wszystkich tych kolumn.
Przepraszam za ten opis, ponieważ trudno jest wyrazić słowami dokładnie, jak działa złożone złącze zewnętrzne (lub lewe) bez rozwlekłości.