Czy istnieje sposób wymuszenia odroczonego rozpoznawania nazw, nawet jeśli tabela istnieje podczas tworzenia procedury składowanej?

10

Podczas tworzenia procedury składowanej w SQL Server możesz odwoływać się do tabel, które nie istnieją. Ale jeśli tabela istnieje, to każda kolumna, do której odwołujesz się w procedurze, musi istnieć w tej tabeli ( rozpoznawanie nazw odroczonych ).

Czy można polecić SQL Serverowi odroczenie rozpoznawania nazw wszystkich tabel, do których istnieją odniesienia w procedurze, niezależnie od tego, czy istnieją? Chcę zachować ogólne sprawdzanie składni, więc nawet gdyby było to możliwe, włamanie definicji procedury składowanej do tabeli systemowej nie jest opcją.

Spodziewam się, że moje zapytanie może wydawać się nieco dziwne , więc oto kilka podstaw: automatycznie generuję definicje tabel i procedury składowane z aplikacji napisanej w C # i bardzo trudno jest mi zmienić kod, aby zamówić zmiany zgodnie z potrzebami SQL im. Mój kod „gwarantuje”, że schemat jest spójny w ramach transakcji, ale obecnie nie mogę zagwarantować, że kolumny tabeli zostaną zdefiniowane przed zdefiniowaniem procedury składowanej, która się do nich odwołuje.

Poniżej znajduje się kanoniczny przykład kodu SQL utworzonego przez C #, który „ilustruje” problem, który próbuję rozwiązać.

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

Możliwe jest , że naprawię to w kodzie C #, ale mam nadzieję na proste „magiczne” ulepszenie, które mogę pobrać z SQL. Zaoszczędzi mi to dużo czasu.

Daniel James Bryars
źródło
1
Czy nie można po prostu przetworzyć wszystkich zmian schematu przed utworzeniem / zmianą jakichkolwiek procedur? Dlaczego procedura musi istnieć, zanim tabela będzie poprawna?
Aaron Bertrand
Korzystam teraz z tej opcji w kodzie. Sposób generowania kodu SQL jest dość skomplikowany (to był prosty przykład), ale wygląda na to, że nie będzie tak duży jak PITA, jak myślałem.
Daniel James Bryars
2
Można to obejść, oczywiście, wypełniając procedury składowane dynamicznym SQL-em - ale nie wyobrażam sobie, aby wygenerować skrypt do obsługi zmian schematu, wówczas procedury przechowywane byłyby tak trudne. Nie ma zbyt wielu opcji, które mogłyby dyktować sposób działania odroczonego rozpoznawania nazw. Jedyną propozycją książek, którą znam, a przynajmniej mogę wywnioskować, że są zainteresowani zabawą, jest w rzeczywistości inny sposób - bardziej szczegółowy - patrz sommarskog.se/strict_checks.html ).
Aaron Bertrand
Dobry pomysł na dynamiczny SQL. Mam ten sam problem z wyzwalaczami, indeksami, widokami, procesami i funkcjami. Ale zmieniłem kod tak, aby po prostu wprowadzał zmiany w tabelach, następnie indeksach, następnie wyzwalaczach, następnie funkcjach, a następnie sprocach.
Daniel James Bryars
Lubię sugestie sommarskoga, zdecydowanie pomogą uniknąć błędów. Gdyby wdrożyli opcję Strict, mogliby także ponownie ocenić wszystkie sprocy „Strict ON”, gdy nastąpi zmiana tabeli, aby zobaczyć, czy to psuje istniejące sproki - oczywiście trzeba wtedy mieć „logiczną transakcję na DDL”, więc może następnie zmienić tabelę i Sprocs jako jedną jednostkę.
Daniel James Bryars

Odpowiedzi:

6

Nie.

Czuję się naprawdę winny, pisząc to, ale nie, niestety. Po raz pierwszy usłyszałem o tym przypadku użycia i ma to sens. Najlepiej przesłać prośbę o to na http://connect.microsoft.com, a twoje wnuki będą mogły to zrobić. ;-)

Brent Ozar
źródło
5

Na wypadek, gdybyś był nadal zainteresowany, istnieje potencjalne obejście, które możesz zastosować. Oto zaktualizowany kod, który wprowadza #deferResolutiontabelę tymczasową do każdego zapytania w procedurze. Ponieważ tabela tymczasowa będzie istnieć tylko w czasie wykonywania, procedura jest w stanie skompilować, nawet jeśli odpowiednie kolumny jeszcze nie istnieją myTable.

Otrzymasz nawet ten sam plan wykonania (bez odniesienia do #deferResolutiontabeli) dla każdej instrukcji w procedurze, ponieważ optymalizator zapytań może udowodnić, że WHERE NOT EXISTSzawsze ocenia to jako prawdziwe.

To powiedziawszy, jest to okropny hack prezentowany głównie z myślą o interesie intelektualnym i może się zdarzyć, że załamie się. Jak wspomina Aaron, prawdopodobnie lepiej byłoby wprowadzić wszystkie zmiany schematu we właściwej kolejności.

--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
źródło