Es gibt mehrere Möglichkeiten, mit fehlenden Zeilen umzugehen, aber bei allen geht es darum, einen anderen Datensatz zu haben, der mit Ihren aktuellen Ergebnissen kombiniert werden kann.
Das könnte von Ihren Ergebnissen abgeleitet werden, erstellt von einem CTE oder einem anderen Prozess (wie Ihrem Beispiel) oder (meine Präferenz) durch die Verwendung einer permanenten Vorlage sich dagegen anschließen.
Die Vorlage in Ihrem Fall könnte einfach eine Datumstabelle sein, wie Ihr @datesTBL. Der Unterschied besteht darin, dass es im Voraus erstellt wird, z. B. mit Daten im Wert von 100 Jahren.
Ihre Abfrage ähnelt dann möglicherweise Ihrem Beispiel, aber ich würde Folgendes versuchen ...
SELECT
dt.tempDate ,
InstructorID, EventStart,
EventEnd, cancelled,
cancelledInstructor,
EventType, DevName,
Room, SimLocation,
ClassLocation, Event,
Duration, TrainingDesc,
Crew, Notes,
LastAmended, InstLastAmended,
ChangeAcknowledged, Type,
OtherType, OtherTypeDesc,
CourseType
FROM
@datesTBL dt
LEFT OUTER JOIN
OpsInstructorEventsView iv
ON iv.EventStart >= dt.tempDate
AND iv.EventStart < dt.tempDate + 1
AND iv.InstructorID = @InstructorID
WHERE
dt.tempDate >= @StartDate
AND dt.tempDate <= @EndDate
ORDER BY
dt.tempDate,
iv.EventStart
Dadurch wird die Kalendervorlage abgelegt auf der LINKEN Seite und erleichtert so viele Abfragen, da Sie wissen, dass das Datumsfeld des Kalenders immer ausgefüllt ist, immer nur ein Datumswert (kein Zeitteil) ist, in der Reihenfolge ist, einfach zu GRUPPIEREN NACH ist usw.