2010-01-20 26 views
5

Tengo un campo "InsertTime" en una tabla en una base de datos SQL Server 2005 que está predeterminada en "getDate()" cuando el registro se inserta por primera vez en la base de datos. Quiero asegurarme de que esta columna no se actualice nuevamente.SQL Server 2005 - Establecer una columna como de solo lectura

¿Se puede configurar esta columna para que sea de solo lectura o existe una forma mejor de hacerlo sin escribir todo el SQL para los desarrolladores?

+0

Tenía la esperanza de evitar la necesidad de reversiones y sólo tienen de modo que no se puede escribir a. Me gusta tu respuesta. La otra forma de hacerlo, es hacer un en lugar de desencadenar como se muestra a continuación, pero eso debe mantenerse con la tabla. No estoy seguro de cuál sería mejor. – GordyII

Respuesta

1

Escriba un procedimiento almacenado para realizar la actualización en esta tabla y asegúrese de que no toque el campo InsertTime. Luego configure todos los permisos de sus usuarios para que ellos mismos no puedan realizar una actualización sin formato en esta tabla, pero pueden llamar al procedimiento almacenado.

+0

Y haga que el desarrollador escriba el sproc. –

4

Puede implementar un campo de "solo lectura" creando un desencadenador ACTUALIZAR que verifique las actualizaciones de esa columna y luego las devuelva.

IF EXISTS (SELECT name FROM sys.objects 
     WHERE name = 'ReadOnlyInsertTime_tr' AND type = 'TR') 
    DROP TRIGGER dbo.ReadOnlyInsertTime_tr; 
GO 

CREATE TRIGGER ReadOnlyInsertTime_tr 
ON dbo.MyTable 
AFTER UPDATE 
AS 
IF (UPDATE(InsertTime)) 
BEGIN 
ROLLBACK 
-- Raise an informative error 
-- RAISERROR (50009, 16, 10) 
END; 
GO 
+0

+1 Me gusta esta solución; Una cosa que agregaría es que si está escribiendo 'InsertTime' en un disparador' AFTER INSERT', entonces necesita deshabilitar este disparador por la duración de ese disparador. – briantyler

1

Un en lugar de gatillo también puede hacer este trabajo.

CREATE TRIGGER [dbo].[MyTableUpdateTrigger] 
ON [dbo].[MyTable] 
INSTEAD OF UPDATE 
AS 
BEGIN 
    SET NOCOUNT ON 

    UPDATE MyTable 
    SET Column1 = Inserted.Column1 
      ,Column2 = Inserted.Column2 
      -- Don't set this for the "InsertTime" field. 
    FROM Inserted 
    INNER JOIN MyTable 
    ON Inserted.TheKey = MyTable.TheKey 
END 
+0

Entonces, ¿cómo se genera un error si el usuario intenta actualizar la columna prohibida? – Ian

2

Otro enfoque es recrear el valor original de InsertDate. Cuando se actualiza una fila, la fila original se mueve a la tabla (lógica) "eliminada". Así ...

ALTER TRIGGER trgDocuments 
ON dbo.Documents 
FOR INSERT, UPDATE 
AS 

-- For new records set the created date and the updated date to Now 
UPDATE Documents SET DateCreated = GetDate(), DateUpdated = GetDate() Where DocumentId in (SELECT DocumentId From inserted) 

-- For updated records set the created date to the original created date and the updated date to Now 
UPDATE Documents SET DateCreated = (SELECT DateCreated FROM deleted d WHERE DocumentId = d.DocumentId) Where DocumentId in (SELECT DocumentId From deleted) 
UPDATE Documents SET DateUpdated = GetDate() Where DocumentId in (SELECT DocumentId From deleted) 
0

I implementado recientemente una solución muy similar a este y tuvo que trabajar a través de una serie de obstáculos, así que dejo la solución aquí con la esperanza de que le ayudará.

Lo que quería hacer era tener una columna RecordCreated y LastModified que fuera administrada por la base de datos en lugar del agente de usuario. En este caso, RecordCreated sería el momento de la fecha en que se insertó por primera vez, y LastModified sería la última vez que se actualizó la fila. También quería evitar que el usuario modifique estas columnas directamente. Esto es lo que hice:

añadido las dos columnas a mi mesa como columnas SMALLDATETIME anulables:

RecordCreated SMALLDATETIME, 
LastModified SMALLDATETIME 

creado un después del disparo de la mesa:

CREATE TRIGGER dbo.WidgetProductionTrigger ON dbo.WidgetProduction AFTER INSERT, UPDATE AS BEGIN 

El gatillo primero comprueba si el usuario intenté insertar/modificar los valores de mis columnas. Me detectado un problema con la función Update() siempre devuelve true, por lo que se requería un poco de lógica adicional:

DECLARE @RecordCreated SMALLDATETIME; 
SELECT @RecordCreated = RecordCreated FROM INSERTED; 
IF UPDATE(RecordCreated) AND NOT @RecordCreated IS NULL BEGIN 
    RAISERROR('RecordCreated is not user maintainable.', 16, 1); 
    ROLLBACK TRANSACTION; 
    RETURN; 
END; 
DECLARE @LastModified SMALLDATETIME; 
SELECT @LastModified = LastModified FROM INSERTED; 
IF UPDATE(LastModified) AND NOT @LastModified IS NULL BEGIN 
    RAISERROR('LastModified is not user maintainable.', 16, 1); 
    ROLLBACK TRANSACTION; 
    RETURN; 
END; 

A continuación, tiene lógica para añadir los valores requeridos para las columnas después de cada inserción o actualización. Puedo comprobar para ver si el registro está siendo insertado o actualizado y ejecutar la lógica apropiada:

IF EXISTS (SELECT * FROM DELETED) BEGIN 
    UPDATE dbo.WidgetProduction SET 
     LastModified = CAST(GETDATE() AS SMALLDATETIME) 
    WHERE ProductionRecordID IN (SELECT ProductionRecordID FROM INSERTED); 
END ELSE BEGIN 
    UPDATE dbo.WidgetProduction SET 
     RecordCreated = CAST(GETDATE() AS SMALLDATETIME), 
     LastModified = CAST(GETDATE() AS SMALLDATETIME) 
    WHERE ProductionRecordID IN (SELECT ProductionRecordID FROM INSERTED); 
END; 

Esta solución funciona exactamente como se esperaba.

Cuestiones relacionadas