Cómo controlar una versión de un registro en una base de datos


Digamos que tengo un registro en la base de datos y que tanto el administrador como los usuarios normales pueden hacer actualizaciones.

Puede alguien sugerir un buen enfoque/arquitectura cómo controlar cada cambio en esta tabla para que sea posible revertir un registro a una revisión anterior.

Author: Benjamin, 2008-11-27

11 answers

Digamos que tienes una tabla FOO que administradores y usuarios pueden actualizar. La mayoría de las veces puede escribir consultas en la tabla FOO. Días felices.

Entonces, crearía una tabla FOO_HISTORY. Esto tiene todas las columnas de la tabla FOO. La clave principal es la misma que FOO más una columna RevisionNumber. Hay una clave foránea de FOO_HISTORY a FOO. También puede agregar columnas relacionadas con la revisión, como userId y RevisionDate. Poblar los números de revisión en un cada vez mayor moda en todas las tablas *_HISTORY (es decir, de una secuencia de Oráculo o equivalente). No confíe en que solo haya un cambio en un segundo (es decir, no ponga RevisionDate en la clave primaria).

Ahora, cada vez que actualice FOO, justo antes de realizar la actualización, inserte los valores antiguos en FOO_HISTORY. Usted hace esto en algún nivel fundamental en su diseño para que los programadores no pueden perder accidentalmente este paso.

Si desea eliminar una fila de FOO tiene algunas opciones. Cualquiera de las dos cascadas y elimine todo el historial, o realice una eliminación lógica marcando FOO como eliminado.

Esta solución es buena cuando usted está muy interesado en los valores actuales y solo ocasionalmente en la historia. Si siempre necesita el historial, puede poner las fechas de inicio y finalización efectivas y mantener todos los registros en FOO. Cada consulta debe verificar esas fechas.

 137
Author: WW.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-21 19:48:34

Creo que está buscando versionar el contenido de los registros de la base de datos (como lo hace StackOverflow cuando alguien edita una pregunta/respuesta). Un buen punto de partida podría ser mirar algún modelo de base de datos que use revisión seguimiento.

El mejor ejemplo que me viene a la mente es MediaWiki, el motor de Wikipedia. Compare el diagrama de la base de datos aquí, particularmente la tabla de revisiones .

Dependiendo de qué tecnologías esté utilizando, tendrá que encontrar alguna buena algoritmos de diff / merge.

Marque esta pregunta si es para. NET.

 37
Author: CMS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:13

En la BI mundo, usted puede lograr esto mediante la adición de un startDate y endDate a la tabla que desea versión. Al insertar el primer registro en la tabla, el startDate se llena, pero el endDate es nulo. Cuando inserte el segundo disco, también la actualización de la endDate del primer registro con el startDate del segundo registro.

Cuando desee ver el registro actual, seleccione el que tenga endDate como null.

Esto a veces se llama un tipo 2 Lentamente Cambiando la dimensión . Ver también TupleVersioning

 22
Author: Dave Neeley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-27 07:09:35

Actualice a SQL 2008.

Intente usar SQL Change Tracking, en SQL 2008. En lugar de marcas de tiempo y hacks de columnas de lápidas, puede usar esta nueva función para rastrear los cambios en los datos de su base de datos.

MSDN SQL 2008 Seguimiento de cambios

 7
Author: D3vtr0n,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-28 00:36:38

Solo quería agregar que una buena solución a este problema es usar una base de datos temporal . Muchos proveedores de bases de datos ofrecen esta función ya sea desde el primer momento o a través de una extensión. He usado con éxito la extensión temporal table con PostgreSQL pero otros también la tienen. Cada vez que actualice un registro en la base de datos, la base de datos también conserva la versión anterior de ese registro.

 5
Author: wuher,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-10 03:29:28

Dos opciones:

  1. Tener una tabla de historial: inserte los datos antiguos en esta tabla de historial cada vez que se actualice el original.
  2. Audit table - almacena los valores antes y después - solo para las columnas modificadas en una tabla de auditoría junto con otra información como quién actualizó y cuándo.
 4
Author: alok,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-27 09:04:42

No dices qué base de datos, y no lo veo en las etiquetas de post. Si es para Oracle, puedo recomendar el enfoque que está integrado en Designer: use tablas de diario. Si es para cualquier otra base de datos, bueno, básicamente recomiendo la misma manera, también...

La forma en que funciona, en caso de que desee replicarlo en otra base de datos, o tal vez si solo desea entenderlo, es que para una tabla también se crea una tabla de sombra, solo una tabla de base de datos normal, con las mismas especificaciones de campo, además de algunos campos adicionales: como qué acción se realizó por última vez (cadena, valores típicos "INS" para insert, "UPD" para update y "DEL" para delete), datetime para cuándo se llevó a cabo la acción e id de usuario para quién lo hizo.

A través de disparadores, cada acción a cualquier fila de la tabla inserta una nueva fila en la tabla de diario con los nuevos valores, qué acción se realizó, cuándo y por qué usuario. Nunca eliminas ninguna fila (al menos no en los últimos meses). Sí crecerá grande, fácilmente millones de filas, pero puede rastrear fácilmente el valor para cualquier registro en cualquier punto en el tiempo desde que comenzó el diario o las antiguas filas del diario se purgaron por última vez, y quién hizo el último cambio.

En Oracle todo lo que necesita se genera automáticamente como código SQL, todo lo que tiene que hacer es compilarlo/ejecutarlo; y viene con una aplicación CRUD básica (en realidad solo "R") para inspeccionarlo.

 3
Author: bart,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-27 08:10:42

Puede realizar auditorías en una tabla SQL a través de desencadenadores SQL. Desde un disparador puede acceder a 2 tablas especiales (insertadas y eliminadas). Estas tablas contienen las filas exactas que se insertaron o eliminaron cada vez que se actualiza la tabla. En el trigger SQL puede tomar estas filas modificadas e insertarlas en la tabla de auditoría. Este enfoque significa que su auditación es transparente para el programador; no requiere ningún esfuerzo de ellos ni ningún conocimiento de implementación.

El añadido la ventaja de este enfoque es que la auditoría se llevará a cabo independientemente de si la operación sql se llevó a cabo a través de sus archivos DLL de acceso a datos, o a través de una consulta SQL manual; (ya que la auditoría se realiza en el propio servidor).

 2
Author: Doctor Jones,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-05 13:33:45

Yo también estoy haciendo lo mismo. Estoy haciendo una base de datos para los planes de lecciones. Estos planes necesitan flexibilidad de versiones de atomic change. En otras palabras, cada cambio, no importa cuán pequeño sea, a los planes de lecciones debe ser permitido, pero la versión antigua también debe mantenerse intacta. De esa manera, los creadores de lecciones pueden editar planes de lecciones mientras los estudiantes los usan.

La forma en que funcionaría es que una vez que un estudiante ha hecho una lección, sus resultados se adjuntan a la versión que completó. Si a el cambio se realiza, sus resultados siempre apuntarán a su versión.

De esta manera, si se elimina o mueve un criterio de lección, sus resultados no cambiarán.

La forma en que estoy haciendo esto actualmente es manejando todos los datos en una tabla. Normalmente solo tendría un campo id, pero con este sistema, estoy usando un id y un sub_id. El sub_id siempre permanece con la fila, a través de actualizaciones y eliminaciones. El id se incrementa automáticamente. El software del plan de lección enlazará al sub_id más reciente. El los resultados del estudiante se vincularán a la identificación. También he incluido una marca de tiempo para el seguimiento cuando los cambios sucedieron, pero no es necesario manejar el control de versiones.

Una cosa que podría cambiar, una vez que lo haya probado, es que podría usar la idea null de endDate mencionada anteriormente. En mi sistema, para encontrar la versión más reciente, tendría que encontrar el max(id). El otro sistema solo busca endDate = null. No estoy seguro de si los beneficios fuera de tener otro campo de fecha.

Mis dos centavos.
 2
Author: Jordan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-22 23:55:32

Mientras @WW. respuesta es una buena respuesta otra forma es hacer una columna de versión y mantener todas sus versiones en la misma tabla.

Para un enfoque de tabla usted:

  • Utilice una bandera para indicar la última ala Word Press
  • O hacer un desagradable mayor que la versión outer join.

Un ejemplo de SQL del método outer join usando números de revisión es:

SELECT tc.*
FROM text_content tc
LEFT OUTER JOIN text_content mc ON tc.path = mc.path
AND mc.revision > tc.revision
WHERE mc.revision is NULL 
AND tc.path = '/stuff' -- path in this case is our natural id.

La mala noticia es que lo anterior requiere un outer join y las uniones externas pueden ser lento. La buena noticia es que crear nuevas entradas es teóricamente más barato porque puede hacerlo en una operación de escritura sin transacciones (suponiendo que su base de datos es atómica).

Un ejemplo para hacer una nueva revisión para '/stuff' podría ser:

INSERT INTO text_content (id, path, data, revision, revision_comment, enabled, create_time, update_time)
(
SELECT
(md5(random()::text)) -- {id}
, tc.path
, 'NEW' -- {data}
, (tc.revision + 1)
, 'UPDATE' -- {comment}
, 't' -- {enabled}
, tc.create_time
, now() 
FROM text_content tc
LEFT OUTER JOIN text_content mc ON tc.path = mc.path
AND mc.revision > tc.revision
WHERE mc.revision is NULL 
AND tc.path = '/stuff' -- {path}
)

Insertamos usando los datos antiguos. Esto es particularmente útil si dice que solo quería actualizar una columna y evitar el bloqueo optimista y / o transacciones.

El enfoque de bandera y el enfoque de tabla de historial requieren dos filas que se insertarán/actualizarán.

La otra ventaja con el enfoque de número de revisión outer join es que siempre puede refactorizar el enfoque de tabla múltiple más adelante con disparadores porque su disparador debería hacer esencialmente algo como lo anterior.

 2
Author: Adam Gent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-28 02:37:24

Alok sugirió Audit table arriba, me gustaría explicarlo en mi post.

Adopté este diseño de tabla única sin esquema en mi proyecto.

Esquema:

  • id-ENTERO AUTO INCREMENTO
  • username-STRING
  • tablename-STRING
  • oldvalue-TEXT / JSON
  • newvalue-TEXT / JSON
  • createdon-DATETIME

Esta tabla puede contener registros históricos para cada tabla todos en un solo lugar, con el objeto completo historia en un solo registro. Esta tabla se puede rellenar mediante disparadores / ganchos donde cambian los datos, almacenando instantáneas de valor antiguas y nuevas de la fila de destino.

Pros con este diseño:

  • Menos número de tablas a administrar para la administración del historial.
  • Almacena la instantánea completa de cada estado de fila antiguo y nuevo.
  • Fácil de buscar en cada tabla.
  • Puede crear particiones por tabla.
  • Puede definir una política de retención de datos por tabla.

Contras con este diseño:

  • El tamaño de los datos puede ser grande, si el sistema tiene cambios frecuentes.
 1
Author: Hassan Farid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-03 18:36:00