Есть ли способ принудительного разрешения имен, даже если таблица существует при создании хранимой процедуры?

10

При создании хранимой процедуры в SQL Server вы можете ссылаться на несуществующие таблицы. Но если таблица существует, то любой столбец, на который вы ссылаетесь в процедуре, должен существовать в этой таблице ( отложенное разрешение имен ).

Можно ли дать SQL Server команду отложить разрешение имен всех таблиц, на которые есть ссылки в процедуре, независимо от того, существуют они или нет? Я хочу сохранить общую проверку синтаксиса, поэтому, даже если бы это было возможно, взломать определение хранимой процедуры в системной таблице не вариант.

Я ожидаю, что мои просьбы сделать это могут показаться немного странными , поэтому приведу некоторую предысторию: я автоматически генерирую определения таблиц и хранимые процедуры из приложения, написанного на C #, и мне очень трудно изменить код, чтобы упорядочить изменения в соответствии с требованиями SQL их. Мой код «гарантирует», что схема согласована внутри транзакции, но в настоящее время я не могу гарантировать, что столбцы таблицы будут определены до того, как я определю хранимую процедуру, которая ссылается на них.

Ниже приведен канонический пример SQL, созданного C #, который «иллюстрирует» проблему, которую я пытаюсь решить.

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

Это является возможным для меня , чтобы исправить это в C # код, но я надеюсь на простой «магии» Tweak я могу тянуть в SQL. Это сэкономит мне много времени.

Дэниел Джеймс Брайарс
источник
1
Разве вы не можете просто обработать все изменения схемы перед созданием / изменением каких-либо процедур? Почему процедура должна существовать до того, как таблица верна?
Аарон Бертран
Я использую эту опцию в коде сейчас. Способ генерации SQL довольно сложный (это был простой пример), но похоже, что он будет не таким большим, как PITA, как я думал.
Даниэль Джеймс Брайерс
2
Конечно, вы можете обойти это, наполнив ваши хранимые процедуры полным динамического SQL - но я не могу представить, что ваш скрипт будет обрабатывать изменения схемы, тогда хранимые процедуры будут такими же сложными. Существует не так уж много опций, определяющих, как работает отложенное разрешение имен. Единственное предложение о книгах, о которых я знаю или, по крайней мере, могу сделать вывод, что они заинтересованы в развлечениях, - это на самом деле другой способ - сделать его более строгим - см. Sommarskog.se/strict_checks.html ).
Аарон Бертран
Хорошая идея о динамическом SQL. У меня та же проблема для триггеров, индексов, представлений, спроков и функций. Но я изменил код так, чтобы он просто вносил изменения в таблицы, затем в индексы, затем в триггеры, затем в функции, затем в спроки.
Даниэль Джеймс Брайерс
Мне нравятся предложения Соммарског, безусловно, поможет избежать ошибок. Если бы они реализовали опцию Strict, то они также могли бы переоценить все спрэки "Strict ON", когда происходит изменение таблицы, чтобы увидеть, не нарушает ли она существующие спроков - очевидно, что тогда вам потребуется иметь "логическую транзакцию в DDL", чтобы вы могли Затем можно изменить таблицу и Sprocs как одно целое.
Даниэль Джеймс Брайерс

Ответы:

6

Нет.

Я чувствую себя действительно виноватым, просто печатая это, но нет, к сожалению. Это первый раз, когда я слышал об этом сценарии использования, и он имеет смысл. Лучше всего подать запрос на это на http://connect.microsoft.com, и ваши внуки смогут это сделать. ;-)

Брент Озар
источник
5

На тот случай, если вы все еще заинтересованы, есть потенциальный обходной путь, который вы можете использовать. Вот обновленный код, который вводит #deferResolutionвременную таблицу для каждого запроса в процедуре. Поскольку временная таблица будет существовать только во время выполнения, процедура может компилироваться, даже если соответствующие столбцы еще не существуют myTable.

Вы даже получите один и тот же план выполнения (без ссылки на #deferResolutionтаблицу) для каждого оператора в процедуре, так как оптимизатор запросов может доказать, что это WHERE NOT EXISTSвсегда имеет значение true.

Все это говорит о том, что это ужасный хак, представленный в основном для интеллектуального интереса, и может быть крайний случай, когда он сломается. Как упоминает Аарон, вам, вероятно, будет лучше сделать все изменения в вашей схеме в правильном порядке.

--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 
Джефф Паттерсон
источник