В конце попробуйте, пожалуйста:
-- Create a Temporary table for keep Maid_Id and AppointmentDateTime
CREATE TABLE #TEMP
(
Maid_Id INT,
AppointmentDateTime DATETIME
)
-- Select all AppointmentDateTime are present in Appointment
DECLARE db_cursor CURSOR FOR SELECT distinct Appointment.AppointmentDateTime FROM Appointment;
-- Iterate them to insert them into the temporary table
DECLARE @date datetime;
OPEN db_cursor;
FETCH NEXT FROM db_cursor INTO @date;
WHILE @@FETCH_STATUS = 0
BEGIN
INSERT INTO #TEMP (Maid_Id, AppointmentDateTime)
SELECT M.Maid_Id, @date FROM Maid M
WHERE M.Maid_Id NOT IN (
SELECT a.Maid_Id FROM Appointment a
WHERE A.AppointmentDateTime = @date
)
FETCH NEXT FROM db_cursor INTO @date;
END;
CLOSE db_cursor;
DEALLOCATE db_cursor;
-- Create another temporary table to keep all the dates we need
DECLARE @MinDate DATE = '2019-05-10',
@MaxDate DATE = '2019-07-24';
CREATE TABLE #DATES
(
[DATE] DATETIME
)
-- Create a range of dates that we need and insert them in the temporary table. It can cover a wide range of dates like 2000-01-01 to Now
INSERT INTO #DATES
SELECT TOP (DATEDIFF(DAY, @MinDate, @MaxDate) + 1)
Date = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY A.OBJECT_ID) - 1, @MinDate)
FROM SYS.ALL_OBJECTS A
CROSS JOIN SYS.ALL_OBJECTS B;
-- Union all the data
SELECT M.Maid_Id, M.Maid_Name, CONVERT(NVARCHAR(10), T.AppointmentDateTime, 120) [date] FROM #TEMP T
INNER JOIN Maid M ON T.Maid_Id = M.Maid_Id
UNION
SELECT null, 'All People Are Free', CONVERT(NVARCHAR(10), [DATE], 120) FROM #DATES
ORDER BY [date]
DROP TABLE #TEMP
DROP TABLE #DATES
Результат примерно такой: