Без лучшего понимания комментариев вашего поста, я считаю, что этот пример кода примерно то, что вы ищете. Это предполагает, что @year является целым числом (так и должно быть), что @table_name где-то указывается - курсор? и что цель состоит в том, чтобы обрезать таблицу перед выполнением вставки, что, по-видимому, является предыдущим поведением.
WHILE @year < year(getdate())
BEGIN
SET @table_name = QUOTENAME('Link_' + @year);
SET @sql = 'TRUNCATE TABLE ' + @table_name + '; INSERT INTO ' + @table_name + ' (a1, b1, REF, TYPE, Patients)
Select a1, b1, REF, TYPE, Count(Distinct a) Patients
From tb Where DATEPART(YEAR, THRU_DT) = @year
And REF Is Not Null And Active = 1 Group By a1, b1, REF, TYPE'
EXECUTE sp_executesql @sql, N'@year int', @year = @year;
SET @YEAR += 1; -- @year should be an integer, so that's how we handle it throughout
RAISERROR('%d has been processed', 0, 1, @year) WITH NOWAIT;
END