Чи існує спосіб примусового вирішення імені відкладеного, навіть якщо таблиця існує під час створення збереженої процедури?


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. У мене така ж проблема у триггерах, індексах, переглядах, програмах та функціях. Але я змінив код так, що він просто вносить зміни в Таблиці, потім Індекси, потім Тригери, потім функції, а потім проростає.
Даніель Джеймс Брайарс

Мені подобаються пропозиції соммарського, безумовно, допоможуть уникнути помилок. Якщо вони реалізували строгий параметр, вони також могли б переоцінити всі проростки "Строгий ВКЛ.", Коли буде зміна таблиці, щоб побачити, чи вона порушує існуючі паростки - очевидно, вам тоді знадобиться "логічна транзакція на DDL", щоб ви може змінити Таблицю та Sprocs як одну одиницю.
Даніель Джеймс Брайарс

Відповіді:


6

Ні.

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


5

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

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

Все, що сказано, це жахливий хакер, представлений здебільшого з інтелектуального інтересу, і там може бути кращий випадок, коли він руйнується. Як згадує Аарон, вам, швидше за все, буде краще внести всі зміни до схеми у належному порядку.

--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 
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.