Quando forçado a usar sql dinâmico em um proc armazenado, fazemos o seguinte. adicione uma variável de entrada de depuração que é um campo de bits. Se for 0, a instrução exec processará se for 1, então você receberá uma instrução de impressão. Eu sugiro que você faça algo parecido para depurar. Em vez de executar, imprima os resultados do seu SQL ou possivelmente insira o SQL em uma tabela, pois parece estar acontecendo em um loop. Então você pode olhar o sql que foi construído e ver onde deu errado.
Declare debug bit
set debug = 1
...
if debug = 1 Begin Print @SQL End
Else
Begin Exec (@sql) End
alternativamente
Crie uma tabela chamada mydynamiccode_logging (com uma coluna sql com o mesmo comprimento que a instrução sql max, uma coluna rundate e quaisquer outras colunas que você achar necessárias (eu consideraria as variáveis de entrada usadas para compor a instrução sql, o usuário, o aplicativo se mais de um usa este pedaço de código)
Antes de executar a instrução exec, execute algo assim:
insert mydynamiccode_logging (sql, rundate)
values (@sql, getdate())
Agora você também pode adicionar o campo de bits de depuração e registrar apenas quando você o alterou para o modo de depuração ou sempre pode registrar, depende do sistema e quanto tempo extra isso leva para fazer e como o resto do sistema está travado. Você não quer diminuir significativamente o prod registrando.