(NOTE: I'm answering this several days after the original post because it raises an interesting question.)In the data provided there actually isn't a row missing for 1:45, its timestamp is 1:44:59.727. Log entries prior to 1:46 all have timestamps less than one second before the target time, then it switched to less than one second after. To account for this, the SQL should allow for a "gap" of 1 or more seconds before and after the target time.Suggested approach:1. Create a permanent table, daily_minutes, containing one row for each minute in a day (60 * 24 = 1440 rows).2. Write a query that returns missing rows by comparing log timestamp to daily_minutes (allowing before/after gap).NOTE: INSERT of missing rows is more complicated, you have to figure out what "average" to use, and deal with things like multiple consecutive missing rows.------------------- STEP 1: CREATE and load table daily_minutes (only need to do this once)------------------- DROP table if it already existsIF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'daily_minutes') DROP TABLE daily_minutes;CREATE TABLE daily_minutes(minute_num INT, minute_ts TIME);DECLARE @minute_num INT, @minute_ts TIME, @NTot INT; SELECT @minute_num = 1, @minute_ts = '00:00:00', -- start at 12AM @NTot = (60 * 24); -- 1440 minutes in a day-- Loop to INSERT a row for each minuteWHILE (@minute_num <= @NTot)BEGIN INSERT INTO daily_minutes SELECT @minute_num, @minute_ts; SELECT @minute_num = @minute_num + 1; -- increment by 1 SELECT @minute_ts = DATEADD(minute, 1, @minute_ts); -- increment by 1 minuteEND;------------------- STEP 2: SQL to identify missing rows-- (NOTE: Log table name = log_table, columns = serial, advance, log_ts)-----------------DECLARE @log_day DATETIME, -- the day of the log rows @gap INT; -- allowed gap before/after each minuteSELECT @log_day = CONVERT(CHAR(10), getdate()-1, 120), -- yesterday 12AM @gap = 1; -- 1 second before or after-- CTE includes rows for target minutes that DO exist in the log table-- (DATEADDs allow for the before/after gap);WITH CTE AS( SELECT DM.minute_num, DM.minute_ts, LT.serial, LT.average, LT.log_ts FROM daily_minutes DM INNER JOIN log_table LT ON LT.[log_ts] BETWEEN DATEADD(s, -@gap, @log_day + DM.minute_ts) AND DATEADD(s, +@gap, @log_day + DM.minute_ts))-- Query returns rows for minutes that are NOT in CTESELECT (@log_day + DM.minute_ts) AS missed_target_ts, DM.minute_num AS DM_minute_num, DM.minute_ts AS DM_minute_ts FROM daily_minutes DM WHERE DM.minute_num BETWEEN (SELECT MIN(minute_num) FROM CTE) AND (SELECT MAX(minute_num) FROM CTE) AND NOT EXISTS (SELECT 1 FROM CTE WHERE minute_num = DM.minute_num);