2009-06-05 8 views
7

Quels types d'astuces sql vous utilisez pour entrer des données dans deux tables avec une référence circulaire intermédiaire. L'employé appartient à un département, un département doit avoir un gestionnaire (chef de département).Gestion de la référence circulaire lors de la saisie de données dans SQL

Dois-je désactiver les contraintes pour que l'insertion se produise?

+0

Cela semble un schéma étrange pour moi, pouvez-vous expliquer pourquoi vous avez les relations de cette façon? – Bob

+3

Est-ce que EmployeeId dans votre département table comme un directeur de département ou quelque chose? –

+0

Dans Oracle, le "truc" est de définir la clé étrangère (s) DEFERRABLE. – spencer7593

Répondre

5

Q: Dois-je désactiver les contraintes pour que l'insertion se produise?
A: Dans Oracle, non, pas si les clés étrangères sont DEFERRABLE (voir exemple ci-dessous)

Pour Oracle:

 
    SET CONSTRAINTS ALL DEFERRED; 
    INSERT INTO Departments values ('foo','dummy'); 
    INSERT INTO Employees values ('bar','foo'); 
    UPDATE Departments SET EmployeeID = 'bar' WHERE DepartmentID = 'foo'; 
    COMMIT; 

Let Déballons que:

  • (la validation automatique doit être désactivée)
  • différer l'application de la contrainte de clé étrangère
  • insérer une ligne à la table Département avec une valeur « factice » pour la colonne FK
  • insérer une ligne à la table des employés FK référence au Département
  • remplacer la valeur « factice » dans le département FK en référence réelle
  • Réactivez l'application des contraintes

REMARQUES: la désactivation d'une contrainte de clé étrangère prend effet pour toutes les sessions, Retarder une contrainte est à un niveau de transaction (comme dans l'exemple), ou au niveau de la session (ALTER SESSION SET CONSTRAINTS=DEFERRED;)

Oracle a permis que les contraintes de clé étrangère soient définies comme DEFERRABLE pendant au moins une décennie. Je définis toutes les contraintes de la clé étrangère (naturellement) pour être DEFERRABLE INITIALEMENT IMMEDIATE. Cela conserve le comportement par défaut attendu par tout le monde, mais permet une manipulation sans que les clés étrangères ne soient désactivées.

voir AskTom: http://www.oracle.com/technology/oramag/oracle/03-nov/o63asktom.html

voir AskTom: http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:10954765239682

voir aussi: http://www.idevelopment.info/data/Oracle/DBA_tips/Database_Administration/DBA_12.shtml

[EDIT]

A: Dans Microsoft SQL Server, vous ne pouvez pas différer les contraintes de clés étrangères comme vous le pouvez dans Oracle. Désactiver et réactiver la contrainte de clé étrangère est une approche, mais je frémis à la perspective de 1) l'impact sur les performances (la contrainte de clé étrangère étant vérifiée pour la table ENTIRE lorsque la contrainte est réactivée), 2) la gestion de l'exception (quand?) la réactivation de la contrainte échoue. Notez que la désactivation de la contrainte affectera toutes les sessions, donc tant que la contrainte est désactivée, d'autres sessions pourraient potentiellement insérer et mettre à jour des lignes qui provoqueront l'échec de la réouverture de la contrainte. Avec SQL Server, une meilleure approche consiste à supprimer la contrainte NOT NULL et à autoriser une valeur NULL comme espace réservé temporaire lorsque des lignes sont insérées/mises à jour.

Pour SQL Server:

 
    -- (with NOT NULL constraint removed from Departments.EmployeeID) 
    insert into Departments values ('foo',NULL) 
    go 
    insert into Employees values ('bar','foo') 
    go 
    update Departments set EmployeeID = 'bar' where DepartmentID = 'foo' 
    go 

[/ EDIT]

+1

Nous venons de découvrir que Sybase vous laissera le faire avec SET OPTION WAIT_FOR_COMMIT = 'ON'. Le réglage sur ON retardera la vérification du référentiel jusqu'à ce que vous appeliez COMMIT. SET OPTION WAIT_FOR_COMMIT = 'ON'; insérer dans les employés ... insérer dans les départements ... COMMIT; SET OPTION WAIT_FOR_COMMIT = 'OFF'; Maintenant, il ne manque que MSSQL;) – Tom

+0

-1 "une meilleure approche consiste à supprimer la contrainte NOT NULL" - comment empêcher l'espace réservé temporaire de rester indéfiniment? – onedaywhen

+0

@Tom: merci pour la note utile sur l'activation de la "vérification de contrainte différée" sur Sybase. – spencer7593

0

Oui, dans ce cas, vous devrez désactiver une clé étrangère.

1

Refactorisez le schéma en supprimant la référence circulaire.
Supprimez une colonne d'ID de l'un des schémas de la table.

Departments.EmployeeID ne semble pas appartenir à mon avis.

1

Je ne peux pas penser à une manière non hackish de faire ceci. Je pense que vous devrez supprimer la contrainte ou faire un certain type de valeurs idiotes qui sont mises à jour après toutes les insertions.

Je vous recommande de refactoriser le schéma de base de données. Je ne peux pas penser à des raisons pour lesquelles vous voudriez que cela fonctionne de cette façon.

Peut-être que quelque chose comme, Employee, EmployeeDepartment (EmployeeId, DepartmentId) et Department serait un meilleur moyen d'atteindre le même objectif.

0

Vous devez vous débarrasser définitivement de l'une ou l'autre des références. Ce n'est pas une structure de conception viable. Lequel doit être entré en premier? Département ou employé? À moins que vos départements ne soient tous très gros, la structure n'a pas de sens, car chaque employé devrait avoir un département distinct.

+0

Je ne sais pas pourquoi ce n'est pas une structure de conception viable. L'employé appartient à un département, un département doit avoir un manager (chef de département). – Tom

+1

Aucun département n'a besoin d'avoir un manager. Les postes de chef de département deviennent vacants. Mais ce n'est pas viable parce que vous ne pouvez jamais avoir une situation circulaire de pk/fk et le faire fonctionner avec le piratage pour contourner les contraintes. La nécessité de pirater pour contourner les contraintes est votre premier indice que le design est mauvais. Je voudrais dhavea une table des employés qui est la table parente, une table d'organisation qui comprend la structure organisationnelle et ensuite une table d'affectations qui a la structure à laquelle la personne est assignée et la hiérarchie (qui est ici). Qui a le FK à la fois. – HLGEM

13

Je suppose que votre Departments.EmployeeID est un chef de département. Ce que je ferais est rendre cette colonne nullable; alors vous pouvez créer le département d'abord, puis l'employé.

+1

Aucune raison pour laquelle vous ne pouvez pas avoir une clé étrangère sur un champ pouvant être validé. – Bill

+0

Non, vous ne pouvez pas. Mais vous pouvez toujours mettre un index dessus pour aider sur les jointures ... –

+0

Chaos: Certainement c'est une option. Bill: L'idée était que chaque département doit avoir un chef de département. – Tom

1

Vous pouvez créer une ligne dans la table Département pour « Unassigned »

Pour créer un nouveau service avec un nouvel employé alors vous

  1. Créer l'employé (EmployeeA) dans le « non affecté » Département
  2. Créer le nouveau département (DepartmentA) avec l'employé EmployeeA
  3. Mise à jour EmployeeA être en DepartmentA

Cela n'invaliderait pas votre schéma actuel et vous pourriez configurer une tâche à exécuter régulièrement pour vérifier qu'il n'y a pas de membres du département Non affecté.

Vous devez également créer un employé par défaut pour être l'employé de Unassigned

EDIT:

La solution proposée par le chaos est beaucoup plus simple que

3

Ce problème pourrait être résolu avec des contraintes deferable .Ces contraintes sont vérifiées lorsque la transaction entière est validée, ce qui vous permet d'insérer à la fois l'employé et le département dans la même transaction, en se référant les uns aux autres. (En supposant que le modèle de données a du sens)

+0

Semble comme l'approche décrite par Spencer7593. Quelqu'un sait comment cela dans MSSQL? – Tom

1

Il y a quelques bons modèles que j'ai utilisés. Tous impliquent la suppression du "manager" EmployeeID de la table Department et la suppression de DepartmentID de la table Employee. J'ai vu quelques réponses qui le mentionnent, mais je vais clarifier comment nous l'avons utilisé:

Je finis généralement avec une table de lien de relation EmployeeDepartment - plusieurs à plusieurs, généralement avec des indicateurs comme IsManager, IsPrimaryManager, IsAdmin, IsBackupManager etc., qui clarifie la relation Certains peuvent être contraints de sorte qu'il n'y a qu'un seul gestionnaire principal autorisé par département (bien qu'une personne puisse être un PrimaryManager de plusieurs départements). Si vous n'aimez pas la table unique, vous pouvez avoir plusieurs tables: EmployeeDepartment, ManagerDepartment, etc. mais vous pourriez avoir des situations où une personne est un manager mais pas un employé, etc.

les gens à être membres de plusieurs départements.

Pour un accès simplifié, vous pouvez fournir des vues qui effectuent la jointure de manière appropriée.

Questions connexes