¿Hay alguna forma de forzar la Resolución de nombre diferido incluso si la tabla existe al crear un procedimiento almacenado?

10

Al crear un procedimiento almacenado en SQL Server, puede hacer referencia a tablas que no existen. Pero, si la tabla existe, entonces cualquier columna a la que se refiera en el procedimiento debe existir en esa tabla ( Resolución de nombre diferido ).

¿Es posible indicar a SQL Server que difiera la resolución de nombres de todas las tablas a las que se hace referencia en un procedimiento, independientemente de si existen o no? Quiero mantener la comprobación general de la sintaxis, por lo que, incluso si fuera posible, piratear la definición del procedimiento almacenado en una tabla del sistema no es una opción.

Supongo que pedir esto puede parecer un poco extraño , así que aquí hay algunos antecedentes: genero automáticamente definiciones de tabla y procedimientos almacenados a partir de una aplicación escrita en C # y es muy difícil para mí cambiar el código para ordenar los cambios según lo necesite SQL ellos. Mi código "garantiza" que el esquema es coherente dentro de una transacción, pero actualmente no puedo garantizar que las columnas de la tabla estén definidas antes de definir el procedimiento almacenado que hace referencia a ellas.

A continuación se muestra un ejemplo canónico del SQL creado por C # que "ilustra" el problema que estoy tratando de 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 

Que es posible para mí Para solucionar esto en el código C #, pero estoy esperando por una simple "mágica" ajustar puedo tirar en el SQL. Esto me ahorrará mucho tiempo.

Daniel James Bryars
fuente
1
¿No puede simplemente procesar todos los cambios de esquema antes de crear / modificar algún procedimiento? ¿Por qué debe existir el procedimiento antes de que la tabla sea correcta?
Aaron Bertrand
Estoy buscando esa opción en el código ahora. La forma en que se genera el SQL es bastante complicada (ese fue un ejemplo simple) pero parece que no va a ser tan PITA como pensé.
Daniel James Bryars
2
Puede evitarlo, por supuesto, rellenando sus procedimientos almacenados llenos de SQL dinámico, pero no puedo imaginar generar su script para manejar los cambios de esquema, entonces los procedimientos almacenados serían tan difíciles. No hay demasiadas opciones expuestas para dictar cómo funciona la resolución de nombre diferido. La única propuesta en los libros que conozco, o al menos que puedo inferir que están interesados ​​en entretener, es en realidad la otra forma, haciéndola MÁS estricta, ver sommarskog.se/strict_checks.html ).
Aaron Bertrand
Buena idea sobre el SQL dinámico. Tengo el mismo problema para disparadores, índices, vistas, Sprocs y funciones. Pero he cambiado el código para que solo haga cambios en las Tablas, luego en Índices, luego en Activadores, luego en funciones, luego en sprocs.
Daniel James Bryars
Me gustan las sugerencias de sommarskog, definitivamente ayudarán a evitar errores. Si implementaron una opción estricta, entonces también podrían reevaluar todas las aplicaciones "estrictas" cuando haya un cambio de tabla para ver si rompe las aplicaciones existentes, obviamente, entonces necesitaría tener una "transacción lógica en DDL" para que pueda luego puede cambiar la Tabla y los Sprocs como una unidad.
Daniel James Bryars

Respuestas:

6

No.

Me siento realmente culpable simplemente escribiendo eso, pero no, tristemente. Es la primera vez que escucho sobre este caso de uso, y tiene mucho sentido. Lo mejor es enviar una solicitud en http://connect.microsoft.com y sus nietos podrán hacerlo. ;-)

Brent Ozar
fuente
5

En caso de que todavía esté interesado, existe una posible solución alternativa que puede emplear. Aquí está el código actualizado, que introduce la #deferResolutiontabla temporal para cada consulta en el procedimiento. Debido a que la tabla temporal solo existirá en tiempo de ejecución, el procedimiento puede compilarse aunque las columnas adecuadas aún no existan myTable.

Incluso obtendrá el mismo plan de ejecución (sin referencia a la #deferResolutiontabla) para cada instrucción en el procedimiento debido a la forma en que el optimizador de consultas puede probar que esto WHERE NOT EXISTSsiempre se evalúa como verdadero.

Dicho todo esto, este es un truco terrible presentado principalmente por interés intelectual y podría haber un caso extremo en el que se rompe. Como Aaron menciona, probablemente sería mejor hacer todos los cambios de esquema en el orden correcto.

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