Existe-t-il un moyen de forcer la résolution de nom différée même si la table existe lors de la création d'une procédure stockée?

10

Lors de la création d'une procédure stockée dans SQL Server, vous êtes autorisé à faire référence à des tables qui n'existent pas. Mais, si la table existe, alors toute colonne à laquelle vous faites référence dans la procédure doit exister dans cette table ( résolution de nom différée ).

Est-il possible de demander à SQL Server de différer la résolution de noms de toutes les tables référencées dans une procédure, qu'elles existent ou non? Je veux garder la vérification de la syntaxe générale, donc même si c'était possible, pirater la définition de procédure stockée dans une table système n'est pas une option.

Je m'attends à ce que ma demande de faire cela puisse sembler un peu bizarre , alors voici un peu de contexte: je génère automatiquement des définitions de table et des procédures stockées à partir d'une application écrite en C # et il est très difficile pour moi de changer le code pour ordonner les changements selon les besoins de SQL leur. Mon code "garantit" que le schéma est cohérent dans une transaction, mais actuellement je ne peux pas garantir que les colonnes de la table sont définies avant de définir la procédure stockée qui les référence.

Ci-dessous est un exemple canonique du SQL créé par le C # qui "illustre" le problème que j'essaie de résoudre.

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

Il est possible pour moi de résoudre ce problème dans le code C #, mais j'espère un simple ajustement "magique" que je peux tirer dans le SQL. Cela me fera gagner beaucoup de temps.

Daniel James Bryars
la source
1
Ne pouvez-vous pas simplement traiter toutes les modifications de schéma avant de créer / modifier des procédures? Pourquoi la procédure doit-elle exister avant que le tableau soit correct?
Aaron Bertrand
Je poursuis cette option dans le code maintenant. La façon dont le SQL est généré est assez compliquée (c'était un exemple simple) mais il semble que ce ne sera pas autant un PITA que je le pensais.
Daniel James Bryars
2
Bien sûr, vous pouvez contourner ce problème en remplissant vos procédures stockées de SQL dynamique - mais je ne peux pas imaginer générer votre script pour gérer les modifications de schéma, alors les procédures stockées seraient très difficiles. Il n'y a pas trop d'options exposées pour dicter le fonctionnement de la résolution de nom différée. La seule proposition dans les livres que je connaisse, ou du moins que je peux déduire qu'ils sont intéressés à se divertir, est en fait l'autre sens - en le rendant PLUS strict - voir sommarskog.se/strict_checks.html ).
Aaron Bertrand
Bonne idée sur le SQL dynamique. J'ai le même problème pour les déclencheurs, les index, les vues, les sprocs et les fonctions. Mais j'ai changé le code pour qu'il n'apporte que des modifications aux tables, puis aux index, puis aux déclencheurs, puis aux fonctions, puis aux sprocs.
Daniel James Bryars
J'aime les suggestions de sommarskog, cela aidera certainement à éviter les bugs. S'ils ont implémenté une option Strict, ils pourraient également réévaluer tous les sprocs "Strict ON" quand il y a un changement de table pour voir si cela casse les sprocs existants - vous auriez évidemment besoin d'une "transaction logique sur DDL" pour que vous peut alors changer la table et les Sprocs en une seule unité.
Daniel James Bryars

Réponses:

6

Non.

Je me sens vraiment coupable de taper ça, mais non, malheureusement. C'est la première fois que j'entends parler de ce cas d'utilisation, et c'est parfaitement logique. Mieux vaut en faire la demande sur http://connect.microsoft.com et vos petits-enfants pourront le faire. ;-)

Brent Ozar
la source
5

Au cas où vous seriez toujours intéressé, il existe une solution de contournement potentielle que vous pouvez utiliser. Voici le code mis à jour, qui présente la #deferResolutiontable temporaire à chaque requête de la procédure. Étant donné que la table temporaire n'existera qu'au moment de l'exécution, la procédure est capable de compiler même si les colonnes appropriées n'existent pas encore sur myTable.

Vous obtiendrez même le même plan d'exécution (aucune référence à la #deferResolutiontable) pour chaque instruction de la procédure en raison de la façon dont l'optimiseur de requêtes peut prouver que cela est WHERE NOT EXISTStoujours vrai.

Cela dit, il s'agit d'un terrible piratage présenté principalement pour un intérêt intellectuel et il pourrait y avoir un cas limite où il tombe en panne. Comme Aaron le mentionne, vous feriez probablement mieux de faire tous vos changements de schéma dans le bon ordre.

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