Existe uma maneira de forçar a resolução de nomes adiados, mesmo que a tabela exista ao criar um procedimento armazenado?

10

Ao criar um procedimento armazenado no SQL Server, você pode se referir a tabelas que não existem. Mas, se a tabela existir, qualquer coluna mencionada no procedimento deverá existir nessa tabela ( Resolução de Nome Diferido ).

É possível instruir o SQL Server para adiar a resolução de nomes de todas as tabelas mencionadas em um procedimento, independentemente de elas existirem ou não? Quero manter a verificação geral da sintaxe, portanto, mesmo se possível, invadir a definição de procedimento armazenado em uma tabela do sistema não é uma opção.

Espero que minha solicitação para fazer isso possa parecer um pouco estranha , então, aqui estão alguns antecedentes: eu gero automaticamente definições de tabela e procedimentos armazenados a partir de um aplicativo escrito em C # e é muito difícil para mim alterar o código para ordenar as alterações conforme o SQL precisar eles. Meu código "garante" que o esquema seja consistente em uma transação, mas atualmente não posso garantir que as colunas da tabela sejam definidas antes de definir o procedimento armazenado que as referencia.

Abaixo está um exemplo canônico do SQL criado pelo C # que "ilustra" o problema que estou tentando resolver.

--Say this table already exists.
CREATE TABLE myTable
(
    a NVARCHAR(MAX)
)
GO

--My C# code creates something like this
BEGIN TRAN 
GO

--the stored procedure gets generated first.
CREATE PROCEDURE mySproc
AS
BEGIN
    SELECT a,b FROM myTable
END

--then the table update
ALTER TABLE myTable
    ADD b nvarchar(MAX)

COMMIT TRAN 

Ele é possível para mim para corrigir isso no código C #, mas eu estou esperando por um simples "mágica" ajustar posso puxar o SQL. Isso vai economizar muito tempo para mim.

Daniel James Bryars
fonte
11
Você não pode simplesmente processar todas as alterações de esquema antes de criar / alterar quaisquer procedimentos? Por que o procedimento deve existir antes que a tabela esteja correta?
Aaron Bertrand
Estou buscando essa opção no código agora. A maneira como o SQL é gerado é bastante complicado (esse foi um exemplo simples), mas parece que não será tão PITA quanto eu pensava.
precisa
2
É possível contornar isso, é claro, preenchendo seus procedimentos armazenados cheios de SQL dinâmico - mas não consigo imaginar gerar seu script para lidar com alterações de esquema, pois os procedimentos armazenados seriam muito difíceis. Não há muitas opções expostas para determinar como a resolução de nomes diferidos funciona. A única proposta sobre os livros que eu conheço, ou pelo menos que posso deduzir que eles estão interessados ​​em entreter, é na verdade o contrário - tornando-o mais rigoroso - veja sommarskog.se/strict_checks.html ).
Aaron Bertrand
Boa ideia sobre o SQL dinâmico. Eu tenho o mesmo problema para gatilhos, índices, visualizações, sprocs e funções. Mas eu mudei o código para que ele faça alterações nas Tabelas, nos Índices, nos Triggers, nas funções e nos sprocs.
Daniel James Bryars
Eu gosto das sugestões de sommarskog, definitivamente ajudará a evitar bugs. Se eles implementassem uma opção Strict, também poderiam reavaliar todos os sprocs "Strict ON" quando houver uma alteração na tabela para ver se ele quebra os sprocs existentes - obviamente, você precisaria ter uma "transação lógica no DDL" para que você pode então alterar a tabela e os Sprocs como uma unidade.
Daniel James Bryars

Respostas:

6

Não.

Eu me sinto realmente culpado apenas digitando isso, mas não, infelizmente. É a primeira vez que ouvi falar desse caso de uso e faz todo o sentido. É melhor enviar uma solicitação em http://connect.microsoft.com e seus netos poderão fazer isso. ;-)

Brent Ozar
fonte
5

Caso você ainda esteja interessado, existe uma solução alternativa que você pode empregar. Aqui está o código atualizado, que apresenta a #deferResolutiontabela temporária para cada consulta no procedimento. Como a tabela temporária só existirá em tempo de execução, o procedimento poderá compilar mesmo que as colunas apropriadas ainda não existam myTable.

Você receberá o mesmo plano de execução (sem referência à #deferResolutiontabela) para cada instrução no procedimento devido à maneira como o otimizador de consultas pode provar que isso WHERE NOT EXISTSsempre é avaliado como verdadeiro.

Tudo isso dito, este é um truque terrível apresentado principalmente por interesse intelectual e pode haver um caso de ponta em que ele se quebra. Como Aaron menciona, provavelmente seria melhor fazer todas as alterações no esquema na ordem correta.

--Say this table already exists.
CREATE TABLE myTable
(
    a NVARCHAR(MAX)
)
GO

--My C# code creates something like this
BEGIN TRAN 
GO

--the sproc gets generated first.
CREATE PROCEDURE mySproc
AS
BEGIN
    CREATE TABLE #deferResolution (dummy INT NOT NULL)
    SELECT a,b FROM myTable WHERE NOT EXISTS (SELECT * FROM #deferResolution WHERE 0=1)
END

--then the table update
ALTER TABLE myTable
    ADD b nvarchar(MAX)

COMMIT TRAN 
Geoff Patterson
fonte