2010-08-13 2 views
3

У меня есть этот скрипт изменения SQL, который работает как часть моего NAnt спланированного создания БД или обновления:Почему проверка существующего отказа столбца в SQL?

SET XACT_ABORT ON 
BEGIN TRANSACTION 

PRINT 'Change MyColumn column to MyNewColumn column in MyTable table' 
IF EXISTS (SELECT * 
      FROM sys.columns 
      WHERE Name = 'MyColumn' AND Object_id = OBJECT_ID('[dbo].[MyTable]')) 
BEGIN 
    PRINT '-> Exists, change it' 
    /* NOTE THE NEXT LINE */ 
    SET @Value = (SELECT MyColumn FROM [dbo].[MyTable]) 

    ALTER TABLE [dbo].[MyTable] 
    DROP CONSTRAINT DF_MyTable_MyColumn 

    ALTER TABLE [dbo].[MyTable] 
    DROP COLUMN MyColumn 

    ALTER TABLE [dbo].[MyTable] 
    ADD MyNewColumn nvarchar(20) NULL 

    ALTER TABLE [dbo].[MyTable] 
    ADD CONSTRAINT DF_MyTable_MyNewColumn DEFAULT ('') FOR MyNewColumn 

    PRINT '-> Add values back into table' 
    SET @Dynamic_Sql = 'UPDATE [dbo].[MyTable] SET MyNewColumn = ''' + @Value + '''' 
    EXEC(@Dynamic_Sql) 

    PRINT '-> Alter to NOT NULL' 
    ALTER TABLE [dbo].[MyTable] 
    ALTER COLUMN MyNewColumn nvarchar(20) NOT NULL 
END 
ELSE 
BEGIN 
PRINT '-> Does not exist, skip it' 
END 

Я уже запустил этот скрипт обновления до и внесения изменений в БД (так MyColumn больше не существует) , Но теперь у меня есть новый сценарий, который приходит после этого, но моя «сборка» не будет работать на этой линии этого сценария с:

Msg 207, Level 16, State 1, Line именем 15 Неверного столбца «MyColumn '

, где Строка 15 - это строка FROM sys.columns. Но на самом деле он жалуется на строку, которая у меня есть внутри оператора IF, где я добавил комментарий NOTE. Почему это должно быть поведением? Конечно, имя столбца будет недействительным, если оно больше не существует.

+0

Можете ли вы включить полный сценарий? Или, по крайней мере, следующие 15-20 строк? Имя столбца появляется где-нибудь еще? Как я уже говорил ниже, номер строки часто может быть неточным, и я не вижу, как вы могли получить это сообщение об ошибке для этой строки, считая, что «MyColumn» - это просто строка, а не имя столбца. –

+0

@Tom, я редактировал вопрос, чтобы включить то, что вы просили, и, очевидно, у меня есть некоторые недоразумения относительно операторов IF и корректности скрипта в SQL. –

ответ

2

Включите ли вы разделитель партий GO после создания всех ваших столбцов? Если нет, столбцы не будут созданы к моменту запуска вашего первого запроса, потому что парсер запросов анализирует все это одновременно - во время разбора столбца действительно не существует.

Добавляя разделитель партий GO, вы вынуждаете его анализировать части запроса, которые используют ваши вновь созданные столбцы после фактического создания столбцов.

+0

любая идея error msg относится к строке «FROM sys.columns». –

+0

Номер строки часто неверен, если вы просто сравниваете его со сценарием. SQL Server сбросит счетчик строк, когда он попадет в инструкцию GO. Есть и другие вещи, которые могут сбросить линию #. –

+0

Это сообщение «Line 15» может быть красной селедкой, отбрасывающей вас. Иногда эти сообщения являются неточными в зависимости от того, как вы выполняете запрос. –

2

Проблема (как указывает Дейв Маркл, так что не стесняйтесь принять его ответ) заключается в том, что SQL Server анализирует весь раздел сценария. Он видит, что вы ссылаетесь на MyColumn и этот столбец не существует, поэтому он дает вам ошибку. Не имеет значения, что он находится в IF-заявлении.

Вы можете проверить это легко с помощью этого сценария:

CREATE TABLE dbo.Test (my_id int) 
GO 
IF (1=0) 
    SELECT blah FROM Test 

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

EDIT: Вот одно из возможных решений. Я еще не прошел через ссылку Мартина, но это может быть другое.

CREATE FUNCTION dbo.Get_my_id() 
RETURNS INT 
AS 
BEGIN 
    DECLARE @my_id INT 
    SELECT @my_id = blah FROM dbo.Test 
    RETURN @my_id 
END 
GO 
CREATE TABLE dbo.Test (my_id INT) 
GO 
DECLARE @my_id INT 

IF (1=0) 
    SELECT @my_id = dbo.Get_my_id() 
GO 

BTW, если таблица имеет более чем одну строку в нем, вы понимаете, что значение переменной не может быть предсказано, правильно?

+0

@ Тому, я вижу, теперь я следую тому, что говорил Дейв М.. Наверное, мне придется разобраться в этом. –

+0

@ Вы можете отложить его с помощью небольшого обходного пути kludgey! http://stackoverflow.com/questions/3290786/is-it-possible-to-tell-ssms-not-to-check-if-a-column-exists-in-at-sql-script/3291626#3291626 –

+0

Спасибо Мартину. Я опубликовал еще один возможный метод выше. –

Смежные вопросы