Question

Cette question est liée au schéma qui se trouve dans l'un de mes autres questions

Était-ce utile?

La solution

Révision 1 janvier 11

Ok, donc il y a un écart entre l'endroit où je suis assis (fournir des bases de données entièrement auditable, la vôtre étant une exigence particulière de ce) et où vous êtes assis: en fonction de vos questions et commentaires. Ce que nous allons probablement travailler dans le commentaire. Voici une position de départ.

  • Pour fournir cette exigence, il n'y a pas besoin du tout pour: déclencheurs; la reproduction en série; intégrité cassée; etc.

  • Ce n'est pas une exigence temporelle classique, que ce soit, donc pas de besoin pour la capacité "période", mais vous peut .

  • ValidFrom et validTo est une erreur de normalisation: la validTo est donnée qui est facilement déduite; ValidTo dans une rangée quelconque est dupliqué, dans le ValidFrom de la rangée suivante; vous avez une mise à jour d'anomalie (lorsque la mise à jour d'une colonne dans une rangée, il faut en outre mettre à jour l'autre colonne dans la rangée suivante); vous devez utiliser une valeur factice pour « courant ».

    • Tous inutiles, utilisez ValidFrom seulement, et de garder la db propre et pur 5NF.

    • Le caveat est, si PostgreSQL ne peut pas effectuer des sous-requêtes sans tomber dans un tas (ala Oracle), alors tout va bien, Kep validTo.

  

Toutes ces choses sont modifiables dans le système par les utilisateurs, et supprimable.

Eh bien, non. Il est une base de données contenant des informations importantes; avec intégrité référentielle, pas un scratchpad, l'utilisateur ne peut pas simplement marcher jusqu'à et « supprimer » quelque chose. Il en contradiction avec la même exigence des utilisateurs pour maintenir des données historiques (dans la lecture, d'alerte, Acq, action, téléchargement).

  • effacera Cascading ne sont pas autorisés. Ces fonctions sont des cases à cocher pour les non-bases de données, MS types d'accès. Pour les bases de données réelles, les contraintes RI arrêtent les parents d'enfants d'être supprimés.

  • Les clés primaires ne peut pas (ne doit pas) être changé. Par exemple. Identifiant d'utilisateur; LocationID; NetworkSlaveCode ne changera jamais; rappelez-vous, ils sont soigneusement considérés comme Identifiants . Une caractéristique de PKs est qu'ils sont stables.

  • Vous pouvez ajouter de nouveaux utilisateurs; vous pouvez modifier courant Nom de l'utilisateur; mais vous ne pouvez pas supprimer un utilisateur qui a des entrées dans Télécharger, Acquittement, Action.

  

En gros si elle est modifiable, alors il doit être historique (de sorte que exclut les lectures et les alertes).

Aussi ne comprend pas: Téléchargements; Remerciements; Actions.

Et les tables de référence: SensorType; Type d'alerte; ActionType.

Et les nouvelles tables d'histoire:. Ils sont insérés dans, mais ils ne peuvent pas être mis à jour ou supprimés

  

Le problème que je trouve avec le drapeau isObselete est .. Dites si vous modifiez l'emplacement, la clé étrangère capteur sera désormais le point à un enregistrement obselete, ce qui signifie que vous devrez dupliquer chaque enregistrement du capteur. Ce problème empirent de façon exponentielle comme hierachy grossit.

  • Ok, donc faites maintenant vous comprenez le LocationId (FK) en Sensor ne changera pas; il n'y a pas la reproduction en série, etc? Il n'y a pas de problème en premier lieu (et il y a dans ce livre stupide!) Qui empirent de façon exponentielle en second lieu.

  • IsObsolete est insuffisante pour vos besoins. (voir ci-dessous)

  • Le UpdatedDtm l'une quelconque réelle rangée (Reading, etc) identifie le parent (FK à Sensor) à la ligne d'histoire (son AuditedDtm) qui était en vigueur à ce moment.

  • Capacité pleine Relational; Déclarative Refential intégrité, etc.

  • Maintenir la IDEF1X, le concept Relational de fortes Identifiers ... Il n'y a qu'une seule ligne parent actuelle (par ex. Emplacement)

  • Les lignes de l'histoire sont des images de la ligne courante, avant qu'il ne soit modifié, à l'AuditedDtm déclaré. La ligne actuelle (non-histoire) montre la dernière mise à jour uneDDTM, lorsque la ligne a été modifiée.

  • Les AuditedDtm montre la série des entiers de UpdatedDtms pour une clé donnée; et donc je l'ai utilisé pour « partition » la véritable clé dans un sens temporel.

Tout ce qui est nécessaire est une table d'histoire pour chaque table variable. J'ai fourni les tables Hiistory pour quatre tables Identification: Lieu; Capteur; NetworkSlave; et l'utilisateur.

S'il vous plaît lire ceci pour comprendre Auditable au sens comptable .

Modèle de données

Lien vers Modèle de données du capteur avec l'histoire (page 2 contient les tableaux d'histoire et le contexte).

Les lecteurs qui ne sont pas familiers avec la norme de modélisation relationnelle peut trouver notation IDEF1X utile.

Réponse aux commentaires

(1) Ma première question est celle de l'intégrité référentielle avec les données historiques dans la mesure où je ne suis pas sûr qu'il y en a, et s'il y a je ne sais pas comment cela fonctionne. Par exemple, dans SensoryHistory il serait possible d'ajouter un enregistrement qui avait un UpdatedDtm indiquant une date heure avant l'emplacement existait elle-même, si vous voyez ce que je veux dire. Que ce soit en fait une question que je ne suis pas sûr - l'application qui pourrait être sur le dessus

.

(Vous avez soulevé une question similaire dans l'autre question.) Il se peut que les dbs que vous avez vécu ne pas réellement l'intégrité référentielle en place; que les lignes de relations, il y avait seulement pour la documentation; que le RI a été « mis en œuvre dans le code d'une application » (ce qui signifie qu'il n'y a pas RI).

Ceci est une base de données / ISO / CEI norme ANSI SQL. Cela permet intégrité référentielle déclarative. Chaque ligne de relation est mis en œuvre comme PK :: FK référence, une contrainte réelle qui est déclarée. Par exemple:

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)
    ...
Ces contraintes déclarées sont appliquées par le serveur; pas par l'intermédiaire des déclencheurs; pas dans le code de l'application. Cela signifie:

  • Un Sensor avec un LocationId qui n'existe pas dans Location ne peut pas être inséré
  • Un LocationId en Location qui a des lignes dans Sensor ne peut pas être supprimé
  • Un SensorHistory avec un LocationId+SensorNo qui n'existe pas dans Sensor ne peut pas être inséré
  • Un LocationId+SensorNo en Sensor qui a des lignes de SensorHistory ne peut pas être supprimé.

(1.1) Toutes les colonnes devrait avoir des règles et les contraintes de vérification à Contraindre leur gamme de valeurs. Cela en plus du fait que tous les INSERT / UPDATE / DELETE sont des programmes, dans les procédures stockées, donc les accidents ne se produisent pas, et les gens ne marchent pas à la base de données et exécuter des commandes contre elle (Selects) de les exclut.

En général, je reste loin de déclencheurs. Si vous utilisez des procédures stockées et les autorisations normales, alors ceci:

SensoryHistory il serait possible d'ajouter un enregistrement qui avait un UpdatedDtm indiquant une date heure avant l'emplacement lui-même existait, si vous voyez ce que je veux dire

est empêchée. Donc, est l'insertion d'un SensorHistory avec un UpdatedDtm plus tôt que le capteur lui-même. Mais procs ne sont pas déclaratives règles. Toutefois, si vous voulez être doublement sûr (et je veux dire deux fois, parce que les pièces rapportées sont tous via un proc, commande directe par les utilisateurs), alors que, vous devez utiliser un déclencheur. Pour moi, c'est sur le dessus.

(2) Comment indiquer la suppression? Je pourrais simplement ajouter un drapeau à la version non-historique de la table, je suppose.

Je ne sais pas encore. Par exemple. Acceptez-vous que lorsqu'un Sensor est supprimé, il est définitif ... (oui, l'histoire est maintenue)... et puis quand un nouveau est Sensor ajouté au Location, elle aura une nouvelle SensorNo ... il n'y a pas Sensor étant logiquement remplacé par le nouveau, avec ou sans décalage dans le temps?

Du point de vue de l'utilisateur final, via le logiciel, ils devraient pouvoir ajouter, éditer et capteurs supprimer à volonté sans limitation. Mais oui, une fois supprimé, il est supprimé et ne peut pas annuler la suppression. Il n'y a rien pour les arrêter Réaddition un capteur plus tard, mais avec les paramètres exactement les mêmes.

"Supprimer" Locations, NetworkSlaves et Users ainsi.

Ok. Ensuite, la nouvelle Sensor avec les mêmes paramètres, est vraiment nouveau, il a une nouvelle SensorNo, et est indépendant de toute logique Sensor précédente. Nous pouvons ajouter un BOOLEAN IsObsolete aux quatre tables d'identification; il est maintenant identifié comme suffisant. La suppression est maintenant programmable Supprimer.

(2.1) Pour NetworkSensor et LoggerSensor, qui sont en fait dépend de deux parents,: ils sont obsolètes si l'un de leurs parents sont obsolètes. Donc, il n'y a pas de point de leur donner une colonne IsObsolete, qui a un double sens, qui peut être dérivé du parent applicable.

(2.2) Pour être clair, les utilisateurs ne peuvent pas supprimer toutes les lignes de toute transaction et tables Histoire, droit?

(3) Lorsque la mise à jour d'une table, quelle méthode serait préférable d'insérer la nouvelle ligne dans le tableau historique et mettre à jour la table principale? Tout à fait normal instructions SQL dans une transaction peut-être?

Oui. C'est l'utilisation classique d'une opération, selon ACID Propriétés, il est atomique; elle réussit soit in toto ou omet in toto (à retentée plus tard, lorsque le problème est résolu).

(4) Referenced Livre

Le texte définitif et séminal est données temporelles et le modèle Relational C J Date, H Darwen, N A Lorentzos. Comme dans, ceux d'entre nous qui embrassent la RM sont familiers avec les extensions, et ce qui est nécessaire dans le successeur du RM; plutôt que d'une autre méthode.

Le livre référencé est horrible et gratuit. Le PDF est pas un PDF (recherche non, pas d'indexation). Ouvrant MS et Oracle est révélateur; quelques bons morceaux dans beaucoup de couchées peluches. Beaucoup de fausses déclarations. Pas la peine de répondre en détail (si vous voulez un examen approprié, ouvrez une nouvelle question).

(4.1) ValidTo en plus de ValidFrom. grave erreur (identifiée au sommet de ma réponse) que le livre fait; puis permet de résoudre laborieusement. Ne faites pas l'erreur en premier lieu, et vous avez rien à résoudre en second lieu. Si je comprends bien, qui permettra d'éliminer vos déclencheurs.

(4.2) Des règles simples, en prenant les exigences temporelles et de normalisation en compte. Tout d'abord, vous devez comprendre en profondeur (a) l'exigence temporelle et (b) les types de données, l'utilisation correcte et ses limites. Toujours magasin:

  • Instant DATETIME, par exemple. UpdatedDtm

  • Intervalle INTEGER, identifiant clairement l'unité dans le nom de la colonne, par exemple. IntervalSec

  • Période. Cela dépend ou en conjonction avec disjointe.

    • Pour en conjonction avec, cette exigence qui est, (4.1) applique: l'utilisation d'un DATETIME; la fin de la période peut être dérivée à partir du début de la période de la ligne suivante.
    • Pour les périodes disjointes, oui, vous avez besoin de 2 x DateTimes, par exemple, RentedFrom et RentedTo avec des écarts entre les deux.

(4.3) Ils mess avec le « temporel clé primaire », ce qui complique le code (en plus d'exiger des déclencheurs pour contrôler la mise à jour Anomaly). Je l'ai déjà livré un environnement propre (éprouvée) temporelle clé primaire.

(4.4) Ils mess avec des valeurs fictives, des valeurs non réelles et des valeurs NULL « Maintenant ». Je ne permets pas de telles choses dans une base de données. Puisque je ne suis pas stocker les ValidTo dupliquée, je n'ai pas le problème, il n'y a rien à résoudre.

(4.5) On peut se demander pourquoi un 528 page "manuel" est disponible gratuitement sur le web, sous forme de PDF pauvres.

(5) I [un utilisateur] pourrait tranquilliser supprimer joyeusement toutes les lignes LocationHistory par exemple, (ne laissant que la version actuelle dans le tableau de localisation) - même si il peut exister une ligne SensorHistory que sur le plan conceptuel « appartient » à une version précédente de l'emplacement, si cela fait sens.

Il n'a pas de sens pour moi, il y a encore une lacune dans la communication que nous devons fermer. S'il vous plaît garder l'interaction jusqu'à ce qu'il soit fermé.

  • Dans une véritable base de données (norme ISO / IEC / ANSI SQL), nous pas GRANT INSERT / UPDATE / autorisation SUPPRIMER aux utilisateurs. Nous GRANT SELECT et RÉFÉRENCES uniquement (pour les utilisateurs choisis) Tous INSERT / UPDATE / DELETE sont codés dans les transactions, ces moyens stockés procs. Ensuite, nous GRANT EXEC sur chaque procédure stockée aux utilisateurs sélectionnés (RÔLES d'utilisation afin de réduire l'administration).

    • Par conséquent, personne ne peut supprimer une table sans exécuter un proc.

    • Ne pas écrire un proc à supprimer dans une table d'histoire. Ces lignes ne doivent pas être supprimés. Dans ce cas, la non-autorisation et la non-existence de code est la contrainte.

    • Techniquement, toutes les lignes d'histoire sont valides, il n'y a pas de période à vous préoccuper avec. La plus ancienne ligne LocationHistory contient l'image avant de la ligne de l'emplacement d'origine avant qu'il ne soit changé. Les plus jeunes rangées LocationHistory est l'image avant de la ligne en cours de localisation. Chaque ligne LocationHistory entre-deux est thusly valide et applique à la période entre les deux.

    • Pas besoin de « pruneau » ou venir chercher quelques lignes de LocationHistory qui peuvent être supprimés sur la base qu'ils appliquent à une période non utilisée: ils sont tous utilisés . (Définitivement, sans qu'il soit nécessaire de vérifier pour toute cartographie des enfants à une emplacement rangée LocationHistory (s), pour le prouver.)

    • Bottom line:. Un utilisateur ne peut pas supprimer d'une table d'histoire (ou transaction)

    • Ou voulez-vous dire quelque chose de nouveau différent?

    • Remarque J'ai ajouté (1.1) ci-dessus.

(6) a corrigé une erreur dans le DM. Un Alert est une expression de Reading, non Sensor.

(7) Correction des règles de gestion dans l'autre question / réponse à refléter le fait que; et les nouvelles règles exposées dans cette question.

(8) Est-ce que vous comprenez / apprécier, que, puisque nous avons un modèle entièrement IDEF1X conforme, re Identifiants :

  • Les identificateurs sont transportées à travers toute la base, en conservant leur pouvoir. Par exemple. lors de l'inscription Acknowledgements, ils peuvent être joints directement avec Location et Sensor; les tables entre ne doivent pas être lu (et ils doivent être si les clés de Id sont utilisées). Voilà pourquoi il y a des faits moins nécessaires dans une jointures base de données relationnelle (et plus nécessaire dans les jointures un dénormalisées).

  • les sous-types, etc. faudra explorer uniquement lorsque ce contexte particulier est pertinent.

Autres conseils

J'ai couru dans cette situation aussi bien avant. En fonction de la quantité de données que votre essayez de garder la trace, il peut être difficile. Le tableau historique fonctionne bien pour la facilité d'utilisation parfois parce que vous pouvez prendre un « instantané » de l'enregistrement dans la table d'historique, puis effectuez les modifications nécessaires dans la table de production. Il est assez simples à appliquer, mais en fonction de la quantité de données que vous avez et combien de fois il change, vous pouvez vous retrouver avec de très grandes tables historiques.

Une autre option est l'enregistrement de toutes les modifications qui permettent à quelqu'un de « rejouer » ce qui est arrivé et le suivre. Chaque modification est enregistrée dans une table ou un champ (en fonction de vos besoins) qui garde la trace de qui, quand, et ce qui a changé à ce que dire sur le 31 décembre 2010 Bob a changé le statut de « Open » à « Fermé ».

Quel système que vous voulez utiliser dépend généralement de la façon dont you'l nécessité de maintenir / revue / utiliser les données plus tard. rapports automatisés, l'examen par une personne, une combinaison des deux, etc.

En fonction de votre budget et / ou de l'environnement, vous voudrez peut-être envisager d'utiliser la fonction d'archivage de flash-back d'Oracle.

Vous pouvez activer automatique « archivage » des lignes d'une table, puis exécutez une déclaration sur la BaseTable en utilisant quelque chose comme

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

Oracle prend soin de maintenir l'histoire dans une table séparée (ombre). Vous pouvez le faire pour toutes les tables afin que vous pouvez également faire une requête avec une jointure.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top