Pregunta

Esta pregunta se relaciona con el esquema que se puede encontrar en una de mis otras preguntas aquí. Básicamente, en mi base de datos almaceno usuarios, ubicaciones, sensores, entre otras cosas. Todas estas cosas se pueden editar en el sistema por los usuarios, y eliminable.

Sin embargo - cuando un elemento está editado o borrado necesito para almacenar los datos antiguos; Tengo que ser capaz de ver lo que los datos eran antes del cambio.

También hay elementos no editables en la base de datos, tales como "lecturas". Son más de un registro realmente. Las lecturas se registran contra sensores, porque es la lectura de un sensor en particular.

Si genero un informe de lecturas, tengo que ser capaz de ver lo que los atributos para una ubicación o un sensor fue en el momento de la lectura .

Básicamente, debe ser capaz de reconstruir los datos para cualquier punto en el tiempo.

Ahora, he hecho esto antes y tengo trabajo bien mediante la adición de las siguientes columnas para cada tabla editable:

valid_from
valid_to
edited_by

Si valid_to = 9999-12-31 23:59:59 entonces que es el registro actual. Si es igual a valid_to VALID_FROM, a continuación, se elimina el registro.

Sin embargo, nunca estaba contento con los factores desencadenantes que necesitaba usar para hacer cumplir la consistencia de clave externa.

I posiblemente puede evitar los desencadenantes utilizando la extensión de la base de datos "PostgreSQL". Esto proporciona un tipo de columna denominada "período", que le permite almacenar un periodo de tiempo entre dos fechas, y luego se le permite hacer restricciones CHECK para evitar la superposición de períodos. Eso podría ser una respuesta.

Me pregunto aunque si hay otra manera.

He visto gente menciona el uso de tablas históricas especiales, pero no me gusta mucho la idea de maintainling 2 mesas para casi todas las 1 mesa (aunque todavía podría ser una posibilidad).

Tal vez podría reducir mi implementación inicial para no molestar a la comprobación de la consistencia de los registros que no son "actual" - es decir, solamente se molestan en comprobar las limitaciones de registros en los que es valid_to 9999-12-31 23:59:59. Después de todo, las personas que utilizan tablas históricas no parecen tener las comprobaciones de restricciones sobre esas tablas (por la misma razón, que había necesidad de disparadores).

¿Alguien tiene alguna idea sobre esto?

PS - el título también menciona la base de datos auditables. En el sistema anterior mencioné, siempre existe el campo edited_by. Esto permitió que todos los cambios sean rastreados por lo que siempre se podía ver que cambió un registro. No estoy seguro de cuánto diferencia que podría hacer.

Gracias.

¿Fue útil?

Solución

revisado 01 Ene 11

Ok, así que hay una brecha entre donde me siento (ofrecer bases de datos totalmente auditables; el suyo es un requisito particular de eso) y donde se sienta: en base a sus preguntas y comentarios. Que vamos a trabajar, probablemente, en el comentario. Aquí está una posición para empezar.

  • Para proporcionar este requisito, no es necesario en absoluto para: disparadores; duplicación de masas; integridad roto; etc.

  • Esto no es un requisito temporal clásico, ya sea, por lo que no necesidad para la capacidad de "período", pero puede .

  • validFrom y validTo es un error Normalización: la validTo son datos que se derivan fácilmente; ValidTo en cualquier fila se duplica, en el validFrom de la siguiente fila; usted tiene una anomalía de actualización (cuando se actualiza una columna en una fila, que, además, tiene que actualizar la otra columna en la fila siguiente); usted tiene que utilizar un valor ficticio de "actual".

    • Todo innecesaria, su uso sólo validFrom, y mantener la db limpio y puro 5NF.

    • La advertencia es, si PostgreSQL no puede realizar subconsultas sin caer en un montón (ala Oracle), entonces bien, kep validTo.

Todas estas cosas se pueden editar en el sistema por los usuarios, y eliminable.

Bueno, no. Es una base de datos que contiene información importante; con la integridad de referencia, no es un bloc de notas, por lo que el usuario puede no sólo subir a ella y "eliminar" algo. Se estará en contradicción con el requisito mismos usuarios para mantener datos históricos (en la lectura; Alerta; Ack; Acción; Descargar).

  • eliminaciones en cascada no están permitidos. Esas funciones son casillas de verificación de los no-bases de datos, tipos de MS Access. Para bases de datos reales, las restricciones RI hacen que los padres con niños que se borre.

  • claves principales no puede (no debe) ser cambiado. P.ej. identificación de usuario; LocationID; NetworkSlaveCode nunca cambian; Recuerde, ellos son considerados cuidadosamente Identificadores . Una característica de PK es que son estables.

  • Se pueden añadir nuevos usuarios; se puede cambiar un actuales nombre del usuario; pero no se puede eliminar un usuario que tiene entradas en Descargar, reconocimiento, acción.

Básicamente, si es editable, entonces tiene que ser histórica (de modo que excluye lecturas y alertas).

también excluye: Descargas; Agradecimientos; Acciones.

Y las Tablas de referencia: SensorType; Tipo de alerta; ActionType.

Y las nuevas tablas de la historia:. Que se insertan en, pero no pueden ser actualizados o eliminados

El problema que encuentro con la bandera isObselete es .. Diga si cambia la ubicación, la clave externa del sensor será ahora apuntan a un registro obsoleto, lo que significa que tendrá que duplicar todos los registros del sensor. Este problema se vuelve exponencialmente peor a medida que la jerarquía se hace más grande.

  • Ok, por lo que ahora usted entiende la LocationId (FK) en Sensor no cambiará; no hay duplicación de masas, etc.? No hay ningún problema en el primer lugar (y no hay en ese libro estúpido!) Que obtiene exponencialmente peor en el segundo lugar.

  • IsObsolete es insuficiente para sus necesidades. (Véase más abajo)

  • El UpdatedDtm en cualquier fila real (Reading, etc) que identifica el Padre (FK Sensor) Historia fila (su AuditedDtm) que estaba en vigor en el momento.

  • Capacidad completa relacional; Declarativa Refential integridad, etc.

  • Mantener la IDEF1X, el concepto relacional de los identificadores fuertes ... Sólo hay una fila padre actual (por ejemplo. Lugar)

  • Las filas de la Historia son imágenes de la fila actual, antes de que se cambió, en el AuditedDtm indicado. La fila actual (no la historia) muestra la última actualización de unoDDTM, cuando la fila se ha cambiado.

  • Los AuditedDtm muestra toda la serie de UpdatedDtms para cualquier clave dada; y así lo he utilizado para "partición" la verdadera clave en un sentido temporal.

Todo lo que se requiere es una tabla de historia para cada tabla cambiante. He proporcionado las tablas Hiistory durante cuatro mesas Identificando: Ubicación; Sensor; NetworkSlave; y Usuario.

Por favor, lea esto para entender auditable en el sentido de que representan .

Modelo de datos

Sensor Modelo de Datos con la Historia (Página 2 contiene las tablas de historia y el contexto).

Los lectores que no están familiarizados con el estándar de modelado relacional puede encontrar IDEF1X Notación útil.

Respuesta a los comentarios

(1) Mi primer problema es el de la integridad referencial con los datos históricos, en los que no estoy seguro de que hay alguna, y si no es que no estoy seguro de cómo funciona. Por ejemplo, en SensoryHistory sería posible añadir un disco que tenía un UpdatedDtm que indica una fecha y hora antes de la ubicación en sí existió, si se entiende lo que quiero decir. Si este es en realidad un problema que no estoy seguro - hacer cumplir que podría ser sobre la parte superior

.

(Se planteó un problema similar en la otra pregunta.) Puede ser que los dbs que ha experimentado en realidad no tienen la integridad referencial en su lugar; que las líneas de relaciones estaban allí sólo para la documentación; que la RI se "implementado en código de la aplicación" (que significa que no hay RI).

Esta es una base de datos ISO / IEC / ANSI SQL. Eso permite integridad referencial declarativa. Cada línea de Relación se implementa como un PK :: FK referencia, una restricción real que se declara. Por ejemplo:

CREATE TABLE Location
    ...
    CONSTRAINT UC_PK
        PRIMARY KEY (LocationId)
    ...
CREATE TABLE Sensor
    ...
    CONSTRAINT UC_PK
        PRIMARY KEY (LocationId, SensorNo)
    CONSTRAINT Location_Sensor_fk
        FOREIGN KEY (LocationId)
        REEFERENCES Location(LocationId)
    ...
CREATE TABLE SensorHistory
    ...
    CONSTRAINT UC_PK
        PRIMARY KEY (LocationId, SensorNo, UpdatedDtm))
    CONSTRAINT Sensor_SensorHistory_fk
        FOREIGN KEY (LocationId, SensorNo)
        REEFERENCES Sensor (LocationId, SensorNo)
    ...
Esas restricciones se aplican declarados por el servidor; no a través de disparadores; no en código de aplicación. Eso significa:

  • A Sensor con un LocationId que no existe en Location no se puede insertar
  • A LocationId en Location que tiene filas en Sensor no se puede eliminar
  • A SensorHistory con un LocationId+SensorNo que no existe en Sensor no se puede insertar
  • Una LocationId+SensorNo en Sensor que tiene filas en SensorHistory no se puede eliminar.

(1.1) Todas columnas debe tener reglas y restricciones CHECK que limitan su rango de valores. Que además del hecho de que todos los INSERT / UPDATE / DELETE son programáticos, dentro de procedimientos almacenados, por lo tanto, los accidentes no suceden, y la gente no caminar hasta la base de datos y ejecutar comandos en contra de ella (exceptúa selecciona).

En general me mantenga alejado de los desencadenantes. Si está utilizando procedimientos almacenados, y los permisos normales, entonces esto:

en SensoryHistory sería posible añadir un disco que tenía un UpdatedDtm que indica una fecha y hora antes de la ubicación en sí existió, si se entiende lo que quiero decir

se evita. También lo es la inserción de un SensorHistory con un UpdatedDtm antes que el propio sensor. Pero procsos no son reglas declarativas. Sin embargo, si quieres estar doblemente seguro (y me refiero por partida doble, ya que los insertos son todos a través de un proc, mando directo por los usuarios), entonces seguro, usted tiene que utilizar un disparador. Para mí, esto es en la parte superior.

(2) ¿Cómo indico eliminación? Tan sólo pudiera añadir una indicación a la versión no-histórico de la tabla supongo.

No está seguro todavía. P.ej. ¿Usted acepta que cuando se elimina un Sensor, que es definitivo ... (sí, la historia se mantiene)... y luego, cuando se añade un nuevo Sensor a la Location, tendrá un nuevo SensorNo ... no hay Sensor siendo lógicamente reemplazado por uno nuevo, con o sin una brecha en el tiempo?

Desde el punto de vista de un usuario final, a través del software que debe ser capaz de añadir, editar y sensores de borrado a voluntad sin limitación. Pero sí, suprimió una vez que se borra y no pueden recuperarse. No hay nada para detenerlos volver a agregar un sensor tarde aunque con los mismos parámetros exactos.

Y Locations, NetworkSlaves "Borrar", y Users también.

Ok. A continuación, el nuevo Sensor con los mismos parámetros, es verdaderamente nuevo, tiene un nuevo SensorNo, y es independiente de cualquier Sensor lógica anterior. Podemos añadir una BOOLEANA IsObsolete a las cuatro mesas de identificación; ahora se identifica como adecuada. La eliminación se ha convertido en un suave Borrar.

(2.1) Para NetworkSensor y LoggerSensor, que son en realidad depende de dos padres: son obsoletos si alguno de sus padres son obsoletas. Así que no hay punto de darles una columna IsObsolete, que tiene un doble significado, que puede derivarse de la matriz aplicable.

(2.2) Para ser claros, los usuarios no pueden eliminar todas las filas de cualquier transacción y tablas de la historia, ¿verdad?

(3) Al actualizar una tabla, ¿qué método sería mejor para insertar la nueva fila en la tabla histórica y actualizar la tabla principal? Sólo las sentencias SQL normales dentro de una transacción tal vez?

Sí. Ese es el clásico uso de una transacción, de acuerdo con propiedades ácidas, es Atómica; tampoco tiene éxito en toto o no en su totalidad (que se reintenta más tarde, cuando el problema es fijo).

(4) Referenced libro

El texto definitivo y seminal es Temporal de datos y el modelo relacional C J Fecha, H Darwen, N A Lorentzos. Al igual que en, los que abrazan la RM están familiarizados con las extensiones, y lo que se requiere en el sucesor de la RM; en lugar de algún otro método.

El libro de referencia es horrible, y libre. El PDF no es un PDF (sin buscar, sin indexación). Al abrir los MS y Oracle está diciendo; unos pocos bits buenas formulan en una gran cantidad de pelusa. Muchas malas interpretaciones. No vale la pena responder en detalle (si desea una revisión adecuada, abrir una nueva pregunta).

(4.1) ValidTo además de ValidFrom. grave error (tal como se identifica en la parte superior de mi respuesta), que hace que el libro; a continuación, resuelve laboriosamente. No cometa el error en el primer lugar, y no tiene nada que resolver en el segundo lugar. Como yo lo entiendo, que eliminará los factores desencadenantes.

(4,2) Las reglas simples, teniendo ambos requisitos de normalización y temporal en cuenta. En primer lugar, es necesario entender profundamente (a) el requisito temporal y (b) los tipos de datos, el uso correcto y sus limitaciones. Siempre tienda:

  • instantánea como DATETIME, por ejemplo. UpdatedDtm

  • Intervalo como INTEGER, identificando claramente la unidad en el nombre de la columna, por ejemplo. IntervalSec

  • Periodo. Depende de la conjunción o disyunción.

    • En conjunción, que este requisito es, (4.1) se aplica: uso de una sola DATETIME; el final del periodo se puede derivar desde el principio del período de la siguiente fila.
    • Para períodos disjuntas, sí, se necesitan 2 x datetimes, por ejemplo, RentedFrom y una RentedTo con lagunas en el medio.

(4.3) Se meterse con la "Clave principal Temporal", lo que complica código (además de requerir disparadores para controlar la actualización de anomalías). Ya he entregado una limpia (probada) de clave temporal primaria.

(4.4) Se meterse con valores ficticios, valores que no son reales, y nulos para "Ahora". No permito que tales cosas en una base de datos. Puesto que no soy el almacenamiento de los ValidTo duplicada, no tengo el problema, no hay nada que resolver.

(4.5) uno tiene que preguntarse por qué una página 528 "libro de texto" está disponible gratuitamente en la web, en formato PDF pobres.

(5) I [un usuario] podía acallar felices para eliminar todas las filas LocationHistory por ejemplo, (dejando sólo la versión actual en la tabla de Localización) - a pesar de que puede existir una fila SensorHistory que conceptualmente "pertenece" a una versión anterior de la ubicación, si eso tiene sentido.

No tiene sentido para mí, todavía hay una brecha en la comunicación tenemos que cerrar. Por favor, mantenga interactuar hasta que se cierra.

    base de datos
  • En un verdadero (estándar ISO / IEC / ANSI SQL), que hacemos no GRANT INSERT / UPDATE / DELETE permiso a los usuarios. Nos GRANT SELECT y Referencias Sólo (para los usuarios seleccionados) Todo INSERT / UPDATE / DELETE están codificados en las transacciones, cuyos medios almacenados procs. Luego GRANT EXEC en cada proc almacenado para usuarios seleccionados (roles uso para reducir la administración).

    • Por lo tanto no se puede eliminar de cualquier mesa sin ejecutar un proc.

    • No escriba un proc eliminar de cualquier mesa de Historia. Estas filas no deberían suprimirse. En este caso, la no autorización y la no existencia de código es la restricción.

    • Técnicamente, todas las filas de historia son válidos, no hay período de que preocuparse. La fila LocationHistory más antigua contiene la imagen antes de la fila ubicación original antes de que se cambió. Las filas LocationHistory más jóvenes es el de imagen anterior de la fila de ubicación actual. Cada fila LocationHistory en el medio es válido y thusly se aplica al período en el medio.

    • No hay necesidad de "ciruela" o buscar un par de filas LocationHistory que se pueden eliminar de la base de que se aplican a un período que no se utiliza: que se usan todos . (En definitiva, sin la necesidad de la comprobación de cualquier asignación de Ubicación hijos a cualquier fila LocationHistory (s), para probarlo.)

    • En pocas palabras:. Un usuario no puede eliminar de cualquier tabla Historia (o transacción)

    • O hacer algo diferente otra vez media?

    • Nota He añadido (1.1) anterior.

(6) Corregido un error en la DM. Un Alert es una expresión de Reading, no Sensor.

(7) Se han corregido las reglas de negocio en la otra pregunta / respuesta para reflejar eso; y las nuevas normas expuestas en esta pregunta.

(8) ¿Comprende / apreciar, que ya que tenemos un modelo totalmente compatible IDEF1X, re Identificadores

  • Los identificadores se realizan a través de toda la base de datos, que conserva su poder. P.ej. al enumerar Acknowledgements, que se pueden unir directamente con Location y Sensor; las tablas en el medio no tienen que ser leído (y que debe ser si se utilizan llaves Id). Esto es por qué hay en hechos menos uniones necesarias en una base de datos relacional (y se une a más necesaria en una desnormalizará).

  • Los subtipos, etc necesidad de ser navegado solamente cuando ese contexto particular es relevante.

Otros consejos

Me he encontrado con esta situación antes también. Dependiendo de la cantidad de datos que su están tratando de no perder de vista, puede ser desalentador. La tabla histórica funciona muy bien para facilitar su uso a veces porque se puede tomar una 'instantánea' del registro de la tabla de la historia, a continuación, hacer los cambios necesarios en la tabla de la producción. Es bastante sencillo de implementar, sin embargo, dependiendo de la cantidad de datos que tiene y con qué frecuencia se cambia, puede terminar con tablas muy grandes históricos.

Otra opción es el registro de todos los cambios que permiten que alguien 'replay' lo que sucedió y realizar un seguimiento de la misma. Cada cambio se registra en una tabla o un campo (en función de sus necesidades) que realiza un seguimiento de quién, cuándo y por qué se ha cambiado a lo que decir En diciembre 31 de, 2010 Bob cambió el estado de 'abierto' a 'cerrado'.

¿Qué sistema que desee utilizar por lo general depende de cómo te necesidad de mantener / revisión / utilizar los datos más tarde. Los informes automatizados, revisión por una persona, una combinación de los dos, etc.

Dependiendo de su presupuesto y / o el medio ambiente es posible que desee considerar el uso de función de archivo flashback de Oracle.

Puede activar automática "archivar" de filas en una tabla, y luego ejecutar una declaración sobre la BaseTable usando algo como

SELECT *
FROM important_data
AS OF TIMESTAMP (SYSTIMESTAMP - INTERVAL '5' DAY)

Oracle se encarga de mantener la historia en una tabla separada (sombra). Esto se puede hacer para cualquier mesa de modo que también se puede hacer una consulta con una combinación.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top