Eu tenho um problema em que um procedimento armazenado está gerando um erro porque está tentando executar/validar uma OPENROWSET
consulta dentro dele que na verdade não precisa ser executada.
O procedimento armazenado que se parece com isto:
IF (@flagA = 1)
BEGIN
INSERT INTO #tmpData(Column1, Column2, Column3)
SELECT A, B, C
FROM (
SELECT *
FROM OPENROWSET(
'Microsoft.ACE.OLEDB.12.0',
'Text; HDR=Yes; Database=\\server\tmpFiles',
'SELECT * FROM FileA.txt')
) as T
END
IF (@flagB = 1)
BEGIN
INSERT INTO #tmpData(Column1, Column2, Column3)
SELECT D, E, F
FROM (
SELECT *
FROM OPENROWSET('Microsoft.Ace.OLEDB.12.0',
'Excel 8.0;Database=\\server\tmpFiles\FileB.xls',
'SELECT * FROM [Sheet$]')
) as T
END
IF (@flagC = 1)
BEGIN
INSERT INTO #tmpData(Column1, Column2, Column3)
SELECT G, H, I
FROM (
SELECT *
FROM OPENROWSET('Microsoft.Ace.OLEDB.12.0',
'Excel 8.0;Database=\\server\tmpFiles\FileC.xls',
'SELECT * FROM [Sheet1$]')
) as T
END
Observe que cada OPENROWSET
um faz referência a um arquivo diferente, em um formato diferente, com nomes de colunas diferentes.
Meu problema é que se um dos arquivos não existir, ou existir no formato errado (como alguém carregando um FileB como FileC por engano), recebo um erro quando o procedimento tenta executar, mesmo que essa OPENROWSET
consulta nunca seja destinado a ser executado.
Por exemplo, se FileB não existir e você tentar executar o procedimento com @flagB = 0
, ele lançará um erro dizendo que não pode encontrar o servidor vinculado paraFileB
Ou se um usuário carregar um FileB
como um FileC
por engano e se corrigir removendo FileC
do formulário, ele lançará um erro dizendo que Cannot process the object "SELECT * FROM [Sheet1$]"
na próxima vez que o procedimento for executado porque o FileC não terá uma planilha chamada Sheet1
, mesmo que@flagC = 0
Como posso evitar que o SQL valide as OPENROWSET
consultas se não forem elas que estão sendo executadas?
Existem algumas opções disponíveis. Uma delas é usar SQL dinâmico para suas chamadas de inserção. Dessa forma, a validação não ocorre até que a execução ocorra. Para o seu exemplo, poderia ficar assim:
Nesse caso, a validação não ocorreria até o tempo de execução. A desvantagem é que a solução de problemas fica mais difícil porque agora você está tentando depurar o SQL dinâmico.
Você também pode mesclar as várias instruções separadas em uma.
Uma segunda alternativa é dividir a chamada em procedimentos separados. Eu colocaria isso em um distante segundo lugar, principalmente porque é fácil abusar disso e começar a fingir que os procedimentos armazenados T-SQL são equivalentes aos métodos de estilo C, esquecendo que pode haver diferenças significativas de desempenho. De qualquer forma, mova as instruções INSERT em três procedimentos separados e passe os parâmetros necessários, assim:
Você não poderia fazer isso com uma tabela temporária, então isso pode descartar essa opção, a menos que você tenha uma tabela "temporária" permanente disponível (ou use uma tabela temporária global).
Se você quiser usar uma tabela temporária, poderá alterar a instrução exec para
insert into #tmpData exec InsertFlagA @parms1
.