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

StackOverflow https://stackoverflow.com/questions/543561

Вопрос

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

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

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

Это было полезно?

Решение

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

Может быть, MS предоставит нам команду «CREATE OR ALTER FUNCTION» в SQL Server 2010/2011?:-)

Марк

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

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

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

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

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

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

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

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

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

Предположим, таблица 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

Теперь удалите таблицу Temp

Drop Table TmpT1

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

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

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

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

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

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

ВСТАВИТЬ В MyTable ВЫБРАТЬ * ИЗ MyOtherTable ГДЕ...

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

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

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

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

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

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

/* 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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top