Gibt es eine Möglichkeit, die Auflösung verzögerter Namen zu erzwingen, selbst wenn die Tabelle beim Erstellen einer gespeicherten Prozedur vorhanden ist?

10

Beim Erstellen einer gespeicherten Prozedur in SQL Server dürfen Sie auf Tabellen verweisen, die nicht vorhanden sind. Wenn die Tabelle jedoch vorhanden ist, muss jede Spalte, auf die Sie in der Prozedur verweisen, in dieser Tabelle vorhanden sein ( Auflösung des verzögerten Namens ).

Ist es möglich, SQL Server anzuweisen, die Namensauflösung aller Tabellen, auf die in einer Prozedur verwiesen wird, zu verschieben, unabhängig davon, ob sie vorhanden sind oder nicht? Ich möchte die allgemeine Syntaxprüfung beibehalten. Selbst wenn dies möglich wäre, ist das Hacken der Definition der gespeicherten Prozedur in eine Systemtabelle keine Option.

Ich gehe davon aus, dass meine Aufforderung dazu etwas seltsam erscheint. Hier einige Hintergrundinformationen: Ich generiere automatisch Tabellendefinitionen und gespeicherte Prozeduren aus einer in C # geschriebenen Anwendung, und es ist sehr schwierig für mich, den Code zu ändern, um die Änderungen nach SQL zu ordnen Sie. Mein Code "garantiert", dass das Schema innerhalb einer Transaktion konsistent ist, aber derzeit kann ich nicht garantieren, dass die Tabellenspalten definiert sind, bevor ich die gespeicherte Prozedur definiere, die auf sie verweist.

Unten finden Sie ein kanonisches Beispiel für das von C # erstellte SQL, das das Problem "veranschaulicht", das ich zu lösen versuche.

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

Es ist mir möglich, dies im C # -Code zu beheben, aber ich hoffe auf eine einfache "magische" Optimierung, die ich in SQL durchführen kann. Das spart mir viel Zeit.

Daniel James Bryars
quelle
1
Können Sie nicht einfach alle Schemaänderungen verarbeiten, bevor Sie Prozeduren erstellen / ändern? Warum muss die Prozedur vorhanden sein, bevor die Tabelle korrekt ist?
Aaron Bertrand
Ich verfolge diese Option jetzt im Code. Die Art und Weise, wie SQL generiert wird, ist ziemlich kompliziert (das war ein einfaches Beispiel), aber es sieht so aus, als würde es nicht so viel wie eine PITA sein, wie ich dachte.
Daniel James Bryars
2
Sie können das natürlich umgehen, indem Sie Ihre gespeicherten Prozeduren mit dynamischem SQL füllen - aber ich kann mir nicht vorstellen, Ihr Skript zu generieren, um Schemaänderungen zu verarbeiten, dann wären gespeicherte Prozeduren so schwierig. Es gibt nicht allzu viele Optionen, die bestimmen, wie die verzögerte Namensauflösung funktioniert. Der einzige Vorschlag zu den Büchern, von dem ich weiß oder von dem ich zumindest schließen kann, dass sie an Unterhaltung interessiert sind, ist der andere - strengere - siehe sommarskog.se/strict_checks.html ).
Aaron Bertrand
Gute Idee zum dynamischen SQL. Ich habe das gleiche Problem für Trigger, Indizes, Ansichten, Sprocs und Funktionen. Aber ich habe den Code so geändert, dass nur Änderungen an den Tabellen, dann an den Indizes, dann an den Triggern, dann an den Funktionen und dann an den Sprocs vorgenommen werden.
Daniel James Bryars
Ich mag die Vorschläge von sommarskog, die definitiv dazu beitragen, Fehler zu vermeiden. Wenn sie eine Strict-Option implementiert hätten, könnten sie auch alle "Strict ON" -Scrocs neu bewerten, wenn eine Tabellenänderung vorgenommen wird, um festzustellen, ob vorhandene Sprocs beschädigt werden. Natürlich müssten Sie dann eine "logische Transaktion für DDL" durchführen kann dann die Tabelle und die Sprocs als eine Einheit ändern.
Daniel James Bryars

Antworten:

6

Nein.

Ich fühle mich wirklich schuldig, wenn ich das schreibe, aber nein, leider. Das ist das erste Mal, dass ich von diesem Anwendungsfall gehört habe, und es macht vollkommen Sinn. Am besten senden Sie eine Anfrage auf http://connect.microsoft.com, und Ihre Enkelkinder können dies tun. ;-);

Brent Ozar
quelle
5

Nur für den Fall, dass Sie immer noch interessiert sind, gibt es eine mögliche Problemumgehung, die Sie anwenden können. Hier ist der aktualisierte Code, der die #deferResolutiontemporäre Tabelle in jede Abfrage in der Prozedur einführt . Da die temporäre Tabelle nur zur Laufzeit vorhanden ist, kann die Prozedur kompiliert werden, obwohl die richtigen Spalten noch nicht vorhanden sind myTable.

Sie erhalten sogar den gleichen Ausführungsplan (kein Verweis auf die #deferResolutionTabelle) für jede Anweisung in der Prozedur, da das Abfrageoptimierungsprogramm nachweisen kann, dass dies WHERE NOT EXISTSimmer als wahr ausgewertet wird.

Alles in allem ist dies ein schrecklicher Hack, der hauptsächlich aus intellektuellen Gründen präsentiert wird, und es könnte einen Randfall geben, in dem er zusammenbricht. Wie Aaron erwähnt, ist es wahrscheinlich besser, alle Schemaänderungen in der richtigen Reihenfolge vorzunehmen.

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