2010-01-29 13 views
6

Tengo una tabla de servidor sql con una columna de marca de tiempo. ¿Hay alguna manera de forzar que la columna de marca de hora cambie sin una actualización real del registro?Cómo actualizar la columna de marca de hora del servidor sql sin cambiar los datos de registro

La razón por la que estoy preguntando es porque quiero que la marca de tiempo del registro cambie cuando se inserta/actualiza/elimina un registro en una tabla secundaria.

La marca de tiempo puede no ser la mejor manera de hacerlo. Si no, ¿qué debería hacer? No quiero usar datetime porque no creo que sea una buena forma de versionar. No quiero usar un número entero, porque no quiero tener que leer el valor para incrementarlo.

Sugerencias?

+0

DateTime por lo general se utiliza para LastModified columns..is este algo diferente o se puede aclarar por qué usted no desea utilizar un DateTime? – dan

+1

Leí un artículo sobre por qué el tipo de datos DateTime no se debe usar para el control de versiones y la concurrencia optimista. No recuerdo todos los detalles, pero tenía sentido en ese momento. Creo que fue debido a la precisión del tipo de datos, las actualizaciones podrían ocurrir teóricamente en la misma instancia que causa las condiciones de carrera. –

+0

Solo si la fecha/hora no es proporcionada por la base de datos - DATETIMEs de SQL Server son en fracciones de segundo: http://msdn.microsoft.com/en-us/library/ms187819.aspx –

Respuesta

9

No quiero usar un número entero, porque no quiero tener que leer el valor para incrementarlo.

UPDATE Table SET 
    IntColumn = IntColumn + 1 

Mientras eso técnicamente requieren una lectura, no veo ningún problema con ella.

siempre se puede simplemente actualizar al mismo valor:

UPDATE Table SET 
    SomeColumn = SomeColumn 

que activará la actualización rowversion también.

ADEMÁS: Se podría hacer una vista con el rowversion máxima de los niños:

SELECT Parent.*, MaxChildRowVersion as ChildVersion 
FROM Parent 
JOIN (
    SELECT ParentId, MAX(RowVersion) as MaxChildRowVersion 
    FROM Child 
    GROUP BY ParentId 
) as Child ON 
    Parent.ParentId = Child.ParentId 

Pero, no, no se puede actualizar directamente a una columna rowversion (aunque se puede implementar su propio actualizable con @@ DBTS, disparadores binarios (8) y INSTEAD OF ...)

¿Podría dar ejemplos de su último punto? Suena prometedor

No, realmente no es así. ;) Es demasiado trabajo cuando podrías actualizar al mismo valor en su lugar o usar una vista. Esas son las 2 opciones más fáciles.

Pero, para completar, una columna binaria (8) con un valor predeterminado de @@ DBTS (que devuelve el número de versión de la base de datos) y un activador DESPUÉS ACTUALIZAR que también actualiza la columna binaria al nuevo @@ DBTS darle un tipo de inversión de secuencia de comandos que luego puede actualizar manualmente. Sin embargo, no sería más rápido o mejor que simplemente actualizar alguna otra columna a su mismo valor.

+0

¿Podría darnos ejemplos de su último punto? Suena prometedor –

1

¿Has estudiado el uso de triggers? Parece un ajuste más natural para lo que estás buscando.

Trabajé en una aplicación que tenía sellos de tiempo en todos los ámbitos una vez; exactamente lo que se suponía que íbamos a hacer con ellos resultó ser un poco esquivo, así que los auditamos fuera del esquema. Puedes leer la marca de tiempo en los objetos que creas basándose en los datos y verificar si se modificó cuando vas a actualizar y revertir si ves que los datos están sucios, pero eso es un montón de repetición para no obtener demasiada ganancia (en menos en el dominio en el que estaba trabajando).

+0

Tengo realmente. Pero todavía tengo que hacer algo en mi desencadenante para obtener una columna de marca de tiempo para actualizar. Esa fue mi pregunta. –

0

Lo que voy a hacer, hasta que surja una mejor idea, es agregar una columna DateTime a mi tabla padre llamada DateChildrenChanged.

Agregaré un desencadenador en la tabla secundaria que establecerá la columna DateChildrenChanged en el DateTime actual y, cuando eso suceda, también se actualizará la columna de marca de tiempo en la tabla principal.

De esta manera estoy usando la columna de marca de tiempo para el control de versiones.

Todavía estoy muy abierto a las ideas.

+0

Creo que esa es la mejor manera de hacerlo. Mantenga su TIMESTAMP/ROWVERSION para versionar la fila actual. Si necesita versionar las filas secundarias, también tiene una columna TIMESTAMP/ROWVERSION, –

4

Ronnie,

En primer lugar la sintaxis timestamp está en desuso por Microsoft, por lo que es necesario utilizar rowversion, la segunda rowversion siempre está relacionado con la fila.

De la documentación:

rowversion

Cada base de datos tiene un contador que se incrementa para cada operación de inserción o actualización que se realiza en una tabla que contiene una columna rowversion dentro de la base de datos. Este contador es la base de datos rowversion.

Sin embargo, debido a la forma en que se implementó en el servidor SQL, debe usar activadores para lograr lo que desea.

Algo como esto:

CREATE TRIGGER tgUpdateParentRowVersion ON ChildTable FOR INSERT, DELETE, UPDATE 
AS 
BEGIN 
    /* 
    * The updates below force the update of the parent table rowversion 
    */ 
    UPDATE ParentTable 
     SET ChildUpdate = ChildUpdate + 1 
    FROM ParentTable a 
    JOIN inserted i on a.pkParentTable = i.fkParentTable 

    UPDATE ParentTable 
     SET ChildUpdate = ChildUpdate - 1 
    FROM ParentTable a 
    JOIN deleted  d on a.pkParentTable = d.fkParentTable 
END 
+0

En cuanto a la obsolescencia, pensé que era al revés: rowversion estaba en desuso. Podría estar equivocado ... –

+0

@Ronnie: estás ** equivocado y Paulo tiene razón. TIMESTAMP está en desuso debido a que su nombre causaba mucha confusión (las personas pensaban que había una manera de convertir eso a una fecha y hora). ROWVERSION es la nueva forma de ir –

+0

Me corresponde corregir. Gracias. –

Cuestiones relacionadas