Почему блок T-SQL выдает ошибку, даже если он не должен выполняться?

Я писал (казалось бы) простой фрагмент кода SQL, который удаляет столбец после того, как удостоверится, что столбец существует. Проблема: если столбец НЕ существует, код внутри в предложении IF сообщает, что не может найти столбец! Что ж, дох, поэтому он внутри предложения IF!
Итак, мой вопрос: почему фрагмент кода, который не следует выполнять, дает ошибки?

Вот фрагмент:

IF exists (select * from syscolumns
    WHERE id=object_id('Table_MD') and name='timeout')
BEGIN
    ALTER TABLE [dbo].[Table_MD]
        DROP COLUMN timeout
END
GO

... и вот ошибка:

Error executing SQL script [...]. Invalid column name 'timeout'

Я использую Microsoft SQL Server 2005 Express Edition.

ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
5
0
1 753
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Возможно, он никогда не будет выполнен, но он будет проанализирован на предмет достоверности сервером Sql. Единственный способ "обойти" это - создать блок динамического sql и затем выборочно выполнить его.

Ответ принят как подходящий

IF exists (select * from syscolumns
    WHERE id=object_id('Table_MD') and name='timeout')
BEGIN
    DECLARE @SQL nvarchar(1000)
    SET @SQL = N'ALTER TABLE [dbo].[Table_MD] DROP COLUMN timeout'
    EXEC sp_executesql @SQL
END
GO

Причина: Когда сервер Sql компилирует код, он проверяет его на наличие используемых объектов (если они существуют). Эта процедура проверки игнорирует любые конструкции «IF», ​​«WHILE» и т. д. И просто проверяет все используемые объекты в коде.

Правильный. Вы также получите эту ошибку, если есть временные таблицы, которые использует sproc.

ConcernedOfTunbridgeWells 23.09.2008 17:35

Чтобы уточнить, если временная таблица существует, столбцы будут проверяться при компиляции sproc. Если sproc фактически создает таблицу (например, с помощью select), вам может потребоваться удалить таблицу перед перекомпиляцией sproc.

ConcernedOfTunbridgeWells 23.09.2008 17:36

Вот как я заставил это работать:

Внутри предложения IF я изменил команду ALTER ... DROP ... на exec ('ALTER ... DROP ...')

Кажется, что SQL-сервер проверяет достоверность кода при его синтаксическом анализе и видит, что где-то есть ссылка на несуществующий столбец (даже если этот фрагмент кода никогда не будет выполнен). Использование команды exec(ute) превращает проблемный код в строку, синтаксический анализатор не жалуется, и код выполняется только при необходимости. Вот измененный фрагмент:

IF exists (select * from syscolumns
    WHERE id=object_id('Table_MD') and name='timeout')
BEGIN
    exec ('ALTER TABLE [dbo].[Table_MD] DROP COLUMN timeout')
END
GO

Между прочим, в Oracle есть аналогичная проблема и аналогичный обходной путь с использованием предложения «выполнить немедленно».

Другие вопросы по теме