Given the next example:
CREATE TABLE Appointments
(
fromDate datetime,
toDate datetime,
appointmentMode int
);
INSERT INTO Appointments VALUES
('20190919 11:00:00', '20190919 11:45:00', 0),
('20190919 11:35:00', '20190919 12:00:00', 1),
('20190919 11:00:00', '20190919 12:00:00', 2);
You can either add the SELECT query to the dynamic query:
DECLARE @CMD NVARCHAR(MAX);
SET @CMD = 'SELECT * INTO #T FROM Appointments; SELECT * FROM #T';
EXEC sp_executesql @CMD;
Or use a global temp table:
DECLARE @CMD2 NVARCHAR(MAX);
SET @CMD2 = 'SELECT * INTO ##T2 FROM Appointments;';
EXEC sp_executesql @CMD2;
SELECT * FROM ##T2;
fromDate | toDate | appointmentMode
:------------------ | :------------------ | --------------:
19/09/2019 11:00:00 | 19/09/2019 11:45:00 | 0
19/09/2019 11:35:00 | 19/09/2019 12:00:00 | 1
19/09/2019 11:00:00 | 19/09/2019 12:00:00 | 2
db<>fiddle here
Quoted from MS-Docs (bold is mine)
sp_executesql has the same behavior as EXECUTE with regard to batches, the scope of names, and database context. The Transact-SQL statement or batch in the sp_executesql @stmt parameter is not compiled until the sp_executesql statement is executed. The contents of @stmt are then compiled and executed as an execution plan separate from the execution plan of the batch that called sp_executesql. The sp_executesql batch cannot reference variables declared in the batch that calls sp_executesql. Local cursors or variables in the sp_executesql batch are not visible to the batch that calls sp_executesql. Changes in database context last only to the end of the sp_executesql statement.