Esiste un modo per forzare la risoluzione dei nomi differiti anche se la tabella esiste durante la creazione di una procedura memorizzata?


10

Quando si crea una procedura memorizzata in SQL Server, è possibile fare riferimento a tabelle che non esistono. Tuttavia, se la tabella esiste, qualsiasi colonna a cui fai riferimento nella procedura deve esistere in quella tabella ( Risoluzione dei nomi posticipati ).

È possibile indicare a SQL Server di rinviare la risoluzione dei nomi di tutte le tabelle a cui fa riferimento una procedura, indipendentemente dal fatto che esistano o meno? Voglio mantenere il controllo generale della sintassi, quindi anche se fosse possibile, l'hacking della definizione della procedura memorizzata in una tabella di sistema non è un'opzione.

Mi aspetto che la mia richiesta di fare ciò possa sembrare un po 'strana , quindi ecco alcuni retroscena: generazione automaticamente definizioni di tabelle e procedure memorizzate da un'applicazione scritta in C # ed è molto difficile per me cambiare il codice per ordinare le modifiche di cui SQL ha bisogno loro. Il mio codice "garantisce" che lo schema sia coerente all'interno di una transazione, ma attualmente non posso garantire che le colonne della tabella siano definite prima di definire la procedura memorizzata che le fa riferimento.

Di seguito è riportato un esempio canonico dell'SQL creato dal C # che "illustra" il problema che sto cercando di risolvere.

--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 

E ' è possibile per me per risolvere questo problema nel codice C #, ma sto sperando in un semplice "magia" tweak posso tirare in SQL. Questo mi farà risparmiare un sacco di tempo.


1
Non puoi semplicemente elaborare tutte le modifiche allo schema prima di creare / modificare qualsiasi procedura? Perché la procedura deve esistere prima che la tabella sia corretta?
Aaron Bertrand

Sto perseguendo questa opzione nel codice ora. Il modo in cui viene generato l'SQL è piuttosto complicato (che era un semplice esempio) ma sembra che non sarà tanto un PITA come pensavo.
Daniel James Bryars,

2
Ovviamente puoi aggirarlo riempiendo le tue procedure memorizzate di SQL dinamico, ma non riesco a immaginare di generare il tuo script per gestire le modifiche dello schema, quindi le procedure memorizzate sarebbero così difficili. Non ci sono troppe opzioni esposte per dettare come funziona la risoluzione differita dei nomi. L'unica proposta sui libri che conosco, o almeno che posso dedurre che sono interessati a intrattenere, è in realtà il contrario - rendendolo PIÙ rigoroso - vedi sommarskog.se/strict_checks.html ).
Aaron Bertrand

Buona idea sull'SQL dinamico. Ho lo stesso problema per trigger, indici, viste, Sprocs e funzioni. Ma ho modificato il codice in modo che apporti solo modifiche alle tabelle, quindi agli indici, quindi ai trigger, quindi alle funzioni, quindi agli sprocs.
Daniel James Bryars,

Mi piacciono i suggerimenti di sommarskog, sicuramente aiuterò a evitare i bug. Se implementassero un'opzione Strict, potrebbero anche rivalutare tutti gli sprocs "Strict ON" quando c'è una modifica della tabella per vedere se interrompe gli sprocs esistenti - ovviamente avresti bisogno di avere una "transazione logica su DDL" in modo da può quindi modificare la tabella e gli Sprocs come un'unica unità.
Daniel James Bryars,

Risposte:


6

No.

Mi sento davvero in colpa solo a scriverlo, ma no, purtroppo. È la prima volta che ho sentito parlare di questo caso d'uso e ha perfettamente senso. È meglio inviare una richiesta su http://connect.microsoft.com e i tuoi nipoti saranno in grado di farlo. ;-)


5

Nel caso in cui tu sia ancora interessato, c'è una potenziale soluzione alternativa che puoi impiegare. Ecco il codice aggiornato, che introduce la #deferResolutiontabella temporanea per ogni query nella procedura. Poiché la tabella temporanea esiste solo in fase di runtime, la procedura è in grado di compilare anche se non esistono ancora le colonne appropriate myTable.

Otterrai anche lo stesso piano di esecuzione (nessun riferimento alla #deferResolutiontabella) per ogni istruzione nella procedura a causa del modo in cui Query Optimizer può dimostrare che ciò viene WHERE NOT EXISTSsempre valutato come vero.

Detto questo, questo è un trucco terribile presentato principalmente per interesse intellettuale e potrebbe esserci un caso limite in cui si guasta. Come menziona Aaron, probabilmente sarebbe meglio apportare tutte le modifiche allo schema nell'ordine corretto.

--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 
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.