7

Si configura una columna de tabla para que sea una columna calculada cuya fórmula llame a una función, resulta complicado cambiar esa función subyacente. Con cada cambio, debe encontrar cada columna cuya fórmula haga referencia a la función, eliminar la referencia, guardar la tabla, alterar la función, volver a agregar todo y guardar de nuevo. Incluso los pequeños cambios son pesadillas.Alterar la función SQL a la que hace referencia la columna calculada

¿Puede decirle a SQL Server que no le importa que las fórmulas hagan referencia a la función y que simplemente continúe y cambie la función subyacente?

Detalles adicionales: La columna calculada no se conserva ni se hace referencia mediante una restricción FK porque no es determinista. La función toma en consideración la hora actual. Se trata de la cuestión de si un registro ha expirado o no.

+0

Acepto que esto es un GRAN dolor! ¡Sintiéndolo ahora mismo! –

+0

Tengo el mismo problema.Supongo que hay una buena razón por la cual MS SQL no lo permite, pero aún así, es un verdadero dolor (+1 por duelo compartido) –

Respuesta

5

No, hasta donde yo sé, no puede hacer esto: primero tendrá que eliminar todas las columnas calculadas que hacen referencia a una función, alterar la función y luego volver a crear las columnas calculadas.

¿Quizás MS nos dará un comando "CREAR O ALTERAR FUNCIÓN" en SQL Server 2010/2011? :-)

Marc

+0

Bueno, supongo que no puedes hacer esto. Y eso es lo que dijiste y lo dijiste primero. – colithium

+0

¿De verdad? ¿No podría simplemente eliminar la restricción de la columna, luego alterar la función y luego volver a aplicar la restricción? –

0

Usted podría tratar con un buen esquema de herramienta de comparación, que crean el guión para ti :)

+0

Tengo SQL Compare 8 y maldito si puedo encontrar un comando de menú para hacer esto ... – jcollum

4

Las consecuencias de la ALTER podrían ser enormes.

¿Ha indexado las columnas? ¿Lo usó en una vista con schemabinding? ¿Persistió? Relación de clave externa a ella?

¿Qué sucede si ALTER cambia el tipo de datos, NULLability o determinism?

Es más fácil detener ALTER FUNCTION con dependencias que lidiar con tantos escenarios.

+0

La función depende del tiempo y no puede persistir. Por esa misma razón, no puede tener una restricción FK (aunque la columna SIEMPRE es un valor válido que hace referencia a PK de otra tabla). – colithium

+0

Esta es * su * función, no el caso general. ¿Qué es mejor: no permitir sistemáticamente ALTERAR LA FUNCIÓN con dependencias o permitirla de forma casi aleatoria? – gbn

+0

Mi función no es nada especial, su comportamiento proviene de que no es determinista. Aclaré eso en mi pregunta con una edición. No debería haber efectos negativos causados ​​por el cambio de funciones no deterministas. ¿Pero es posible? – colithium

0

Puede cambiar la columna para que no se compute, y actualizarla mediante TRIGGER.

O podría cambiar el nombre de la tabla a otra cosa, descartar la columna calculada y crear una VISTA en lugar de la tabla original (es decir, con el nombre original de la tabla) e incluir la columna "calculada" que necesita.

EDITAR: tenga en cuenta que esto puede interferir con sus INSERT en el nombre original de la tabla (ahora una VISTA). Obviamente, puede mantener la tabla anterior, descartar la columna calculada y crear una VISTA separada que contenga la columna calculada.

Hemos tenido que trabajar con Columnas computadas suficientes veces para haber decidido que son más problemas de los que obtienen. Insertos Fail-Saf (1), que intentan insertarse en VIEWs en tablas con columnas calculadas, cosas que requieren jugar con SET ARITHABORT y más.

(1) Hemos inserciones a prueba de fallos gustaría:

INSERT INTO MiTabla SELECT * FROM MyOtherTable DONDE ...

que están diseñados para fallar si se añade una nueva columna de una tabla y no el otro. Con Columna Computada tenemos que nombrar explícitamente todas las columnas, lo que nos hace perder esa red de seguridad.

+0

Ese es el problema, el valor de la columna calculada no es determinista. Es decir, si le preguntas qué es, podría decir una cosa y luego un segundo después sin ningún cambio en los datos, podría decir algo diferente. Los disparadores no funcionarán aquí. – colithium

+0

¡Leí que decía que no era determinista, mi mente luego se desvió! Lo siento por eso. – Kristen

1

Supongamos tabla T1 con columnas C1, C2, C3, C4, C5, donde C4 es una columna calculada

también asumir la del C4 referencias de función OldFunc el que desea ser sustituido por NewFunc

En primer lugar, mover las columnas no calculadas a partir de todas las filas de una tabla temporal

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

a continuación, elimine todas las filas de T1

Delete From T1 
go 

Ahora puede modificar la columna C4

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

Ahora ponga los datos guardados en la tabla original

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

Ahora Eliminar La tabla temporal

Drop Table TmpT1 
2

Lo siento por esta respuesta tardía, pero puede ser útil.

Puede usar una función ficticia para cada columna calculada que llame a su función real.

Ejemplo:
La columna calculada utilizan la fórmula: dbo.link_comp ('123')
Esta función adelante los argumentos y llamadas y devolver el dbo.link función ('123') (Su función real)
Ambas funciones solo necesitan usar los mismos argumentos y devolver el mismo tipo.

Luego, la función que está bloqueada es dbo.link_comp y aún se puede ALTERAR dbo.link.
Además, si su función es llamada desde otro SQL, aún puede usar su nombre de función real dbo.link, la función ficticia dbo.link_comp es solo para la columna calculada.

0

Sé que ya es tarde para la fiesta pero estaba teniendo el mismo problema hoy y no encontré nada que resuelva el problema así que rápidamente escribí uno.

Básicamente, crea una tabla temporal que contiene la información de la columna para cada columna calculada con la función, descarta las columnas de las tablas. Luego actualiza su función y deja que vuelva a crear todas las columnas con sus definiciones.

Si tiene que hacer cambios en los parámetros dentro de las definiciones (como necesito) puede simplemente crear una secuencia de esa parte en donde las definiciones se crean de nuevo.

Si ha calculado columnas dentro de índices u otras necesidades, puede ampliar fácilmente el código, pero esto fue más allá del alcance de mis necesidades.

Espero que pueda ser útil para otra persona.

/* 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 
Cuestiones relacionadas