Изменить функцию SQL, на которую ссылается вычисляемый столбец

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

Можете ли вы сказать SQL Server, что вас не волнует, что на функцию ссылаются формулы, и что нужно просто изменить базовую функцию?

Дополнительные сведения. Вычисляемый столбец не сохраняется и на него не ссылается ограничение FK, поскольку оно недетерминировано. Функция учитывает текущее время. Это касается вопроса о том, просрочена запись или нет.


person colithium    schedule 12.02.2009    source источник
comment
Я согласен, что это БОЛЬШАЯ боль! Почувствуйте это прямо сейчас!   -  person Craig Shearer    schedule 27.11.2009
comment
У меня такая же проблема. Я предполагаю, что есть веская причина, по которой MS SQL не позволяет этого, но все же это настоящая боль (+1 за общее горе)   -  person Daniel Brink    schedule 05.12.2012


Ответы (7)


Нет, насколько мне известно, вы не можете этого сделать — вам придется сначала удалить все вычисляемые столбцы, ссылающиеся на функцию, изменить функцию, а затем воссоздать вычисляемые столбцы.

Может быть, MS даст нам команду «СОЗДАТЬ ИЛИ ИЗМЕНИТЬ ФУНКЦИЮ» в SQL Server 2010/2011? :-)

Марк

person marc_s    schedule 12.02.2009
comment
Ну, я полагаю, вы просто не можете этого сделать. И это то, что ты сказал, и ты сказал это первым. - person colithium; 18.02.2009
comment
Действительно? Не могли бы вы просто удалить ограничение из столбца, затем изменить функцию, а затем повторно применить ограничение? - person Mr W; 08.12.2014

Последствия ALTER могут быть огромными.

Вы проиндексировали столбцы? Использовали его в представлении с привязкой схемы? Сохранял это? Отношение внешнего ключа к нему?

Что, если ALTER изменит тип данных, возможность использования NULL или детерминизм?

Легче остановить ALTER FUNCTION с зависимостями, чем иметь дело с таким количеством сценариев.

person gbn    schedule 14.02.2009
comment
Функция зависит от времени и не может быть сохранена. По той же причине он не может иметь ограничение FK (даже если столбец ВСЕГДА оказывается допустимым значением, ссылающимся на PK другой таблицы). - person colithium; 16.02.2009
comment
Это ваша функция, а не общий случай. Что лучше: постоянно запрещать ALTER FUNCTION с зависимостями или разрешать это довольно случайным образом? - person gbn; 16.02.2009
comment
Моя функция не является чем-то особенным, ее поведение обусловлено недетерминированностью. Я пояснил это в своем вопросе с правкой. Не должно быть никаких побочных эффектов, вызванных изменением недетерминированных функций. Но возможно ли это? - person colithium; 16.02.2009

Извините за этот поздний ответ, но он может быть полезен.

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

Пример:
Вычисляемый столбец использует формулу: dbo.link_comp('123')
Эта функция перенаправляет аргументы и вызовы и возвращает функцию dbo.link('123') (ваша реальная функция)
Обе функции просто должны использовать одни и те же аргументы и возвращать один и тот же тип.

Затем блокируется функция dbo.link_comp, и вы по-прежнему можете ИЗМЕНИТЬ dbo.link.
Кроме того, если ваша функция вызывается из другого SQL, вы все равно можете использовать свое настоящее имя функции dbo.link, фиктивную функцию dbo. .link_comp предназначен только для вычисляемого столбца.

person Guillaume Hamilton    schedule 07.01.2015

Предположим, таблица T1 со столбцами C1, C2, C3, C4, C5, где C4 — вычисляемый столбец.

Также предположим, что C4 ссылается на функцию OldFunc, которую вы хотите заменить на NewFunc.

Во-первых, переместите невычисляемые столбцы из всех строк во временную таблицу.

Select C1, C2, C3, C5 into TmpT1 from T1
Go

Затем удалите все строки из T1.

Delete From T1
go

Теперь вы можете изменить столбец C4

Alter table T1 alter column C4 as dbo.NewFunc()
Go

Теперь поместите сохраненные данные обратно в исходную таблицу.

Insert Into T1 (C1,C2,C3,C5) select C1,C2,C3,C5 from TmpT1

Теперь удалите временную таблицу

Drop Table TmpT1
person Stan Amditis    schedule 28.04.2011

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

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

Если вам нужно внести изменения в параметры в определениях (как мне нужно), вы можете просто написать эту часть, где определения создаются снова.

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

Надеюсь, это может быть полезно для кого-то еще.

/* Create temporary table to hold definitions */
CREATE TABLE [#FUNCTION]
(
    [TABLE_NAME] nvarchar(255) NOT NULL,
    [COLUMN_NAME] nvarchar(255) NOT NULL,
    [DEFINITION] nvarchar(255) NOT NULL
)
GO

/* Add data to temp table */
INSERT INTO [#FUNCTION] ( [TABLE_NAME], [COLUMN_NAME], [DEFINITION] )
SELECT TABLE_NAME, COLUMN_NAME, definition FROM INFORMATION_SCHEMA.COLUMNS
INNER JOIN sys.computed_columns ON ( object_id = object_id( TABLE_NAME ) AND name = COLUMN_NAME )
WHERE definition LIKE '%MyFunctionName%'
GO

/* Remove columns */
DECLARE @TABLE_NAME nvarchar(255)
DECLARE @COLUMN_NAME nvarchar(255)

DECLARE c_CursorName CURSOR LOCAL FOR SELECT [TABLE_NAME], [COLUMN_NAME] FROM [#FUNCTION]
OPEN c_CursorName

FETCH NEXT FROM c_CursorName INTO @TABLE_NAME, @COLUMN_NAME

WHILE @@FETCH_STATUS = 0
BEGIN
    EXEC( 'ALTER TABLE [' + @TABLE_NAME + '] DROP COLUMN [' + @COLUMN_NAME + ']' )

    FETCH NEXT FROM c_CursorName INTO @TABLE_NAME, @COLUMN_NAME
END

CLOSE c_CursorName
DEALLOCATE c_CursorName
GO

/* Update function */
-- Update function here
GO

/* Recreate computed columns */
DECLARE @TABLE_NAME nvarchar(255)
DECLARE @COLUMN_NAME nvarchar(255)
DECLARE @DEFINITION nvarchar(255)

DECLARE c_CursorName CURSOR LOCAL FOR SELECT [TABLE_NAME], [COLUMN_NAME], [DEFINITION] FROM [#FUNCTION]
OPEN c_CursorName

FETCH NEXT FROM c_CursorName INTO @TABLE_NAME, @COLUMN_NAME, @DEFINITION

WHILE @@FETCH_STATUS = 0
BEGIN
    EXEC( 'ALTER TABLE [' + @TABLE_NAME + '] ADD [' + @COLUMN_NAME + '] AS ' + @DEFINITION )

    FETCH NEXT FROM c_CursorName INTO @TABLE_NAME, @COLUMN_NAME, @DEFINITION
END

CLOSE c_CursorName
DEALLOCATE c_CursorName
GO

/* Remove temp table */
DROP TABLE [#FUNCTION]
GO
person Storm    schedule 23.06.2015

Вы можете попробовать какой-нибудь хороший инструмент сравнения схем, который создаст для вас скрипт :)

person Community    schedule 13.02.2009

Вы можете сделать столбец невычисляемым и обновить его с помощью TRIGGER.

Или вы можете переименовать таблицу во что-то другое, удалить вычисляемый столбец и создать VIEW вместо исходной таблицы (т. е. с исходным именем таблицы), включая нужный вам «вычисляемый» столбец.

РЕДАКТИРОВАТЬ: обратите внимание, что это может испортить ваши ВСТАВКИ в исходное имя таблицы (теперь VIEW). Очевидно, вы можете оставить старую таблицу, удалить вычисляемый столбец и создать отдельное представление, содержащее вычисляемый столбец.

Нам приходилось обходиться с вычисляемыми столбцами достаточно раз, чтобы решить, что от них больше проблем, чем пользы. Отказоустойчивые вставки(1), попытки вставки в VIEW в таблицы с вычисляемыми столбцами, вещи, требующие взаимодействия с SET ARITHABORT и так далее.

(1) У нас есть отказоустойчивые вставки, такие как:

INSERT INTO MyTable SELECT * FROM MyOtherTable WHERE...

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

person Kristen    schedule 16.02.2009
comment
В том-то и дело, что значение вычисляемого столбца недетерминировано. Это означает, что если вы спросите его, что это такое, он может сказать одно, а через секунду без каких-либо изменений данных он может сказать что-то другое. Триггеры здесь не сработают. - person colithium; 16.02.2009
comment
Я действительно читал, что это было недетерминировано, и тогда мой разум блуждал! Извини за это. - person Kristen; 16.02.2009