2010-06-29 4 views
1

Disons que si j'ai une table « persondata » dans laquelle 4 de ses colonnes sontsql requête aide - comment rejoindre correctement?

FromPersonId, FromEmployeeId, ToPersonId, ToEmployeeId

Tous les enregistrements que jamais ne contient qu'un seul De ** et seul à ** et les deux autres colonnes sont nulles. Aussi FromPersonId et ToPersonId appartiennent à la table "Personne" et FromEmployeeId et ToEmployeeId appartiennent à la table "Employé".

Ma question est: Comment puis-je CORRIGER correctement une table PersonData avec une personne et un employé?

S'il vous plaît noter que j'ai essayé tas de différentes approches, mais quand je fais un compte sur le persondata Je reçois des résultats différents lorsque vous faites une jointure (il montre plus que ce qui est en persondata) ...

Comment devrais-je faire une jointure? devrais-je en faire un pour chaque objet FromPersonId et ToPersonId pour Person et similaire pour l'employé? (Doute que ce soit le cas) ...

Merci,

Voodoo

+0

Si vous êtes intéressé à faire les choses "correctement" - votre structure de table sent le genre (ou je ne comprends pas ce que vous faites). Cela semble être une simple table d'association à deux colonnes, avec PersonID et EmployeeID. Quel est le point des colonnes nulles? – harpo

+0

@Harpo c'est une ancienne application pour laquelle je migre les données et cela a été fait il y a 10-15 ans ... – VoodooChild

+1

Pourquoi obtenir plus de résultats que dans PersonData un résultat incorrect? Si vous avez des valeurs pour FromPersonID et ToPersonID, votre jointure va correspondre à 2 enregistrements dans la table Person –

Répondre

1

Ok, donc il semble que le problème est que si vous vous joignez à personne sur FromPersonID = PersonID et ToPersonId = PersonID, vous obtenez 2 enregistrements pour chaque enregistrement dans PersonData.

Le moyen de contourner ce serait de joindre à 2 copies alias de PersonData afin que vous puissiez attacher les résultats dans la même rangée. Quelque chose comme:

Select * from PersonData 
LEFT JOIN Person p1 on p1.PersonID = FromPersonID 
LEFT JOIN Person p2 on p2.PersonID = ToPersonID 

et essentiellement faire la même chose pour la Défense et des champs des employés

+0

F $ # @ # Joindre gauche était la réponse .... Vous êtes génial :) – VoodooChild

+0

Aussi Rob, tous les bons guides sur la différence entre les différents types de jointures qui m'aideront, quelque chose de pas difficile à suivre :) merci encore. – VoodooChild

+1

np :) Je pense que la principale chose à savoir sur les jointures est simplement qu'une jointure interne ne retournera les résultats que dans les deux tables, où une jointure externe retournera toutes les lignes de la table dominante et les valeurs null pour les champs qui ne correspondent pas. enregistrer dans l'autre tableau. Les jointures internes sont effectuées par défaut si vous ne spécifiez pas. Une jointure à gauche est une jointure externe qui indique simplement que la table dominante est la première spécifiée. Imaginez que vous ayez les valeurs de champ de PersonData sur la gauche, et ensuite nous verrons simplement les valeurs de p1, si elles existent. Maintenant que la combinaison est la nouvelle gauche, et nous "verrouiller" toutes les valeurs de p2. –

2

On dirait qu'il ya 4 possibilités:
FromPerson -> ToPerson
FromPerson -> ToEmployee
FromEmployee - > ToPerson
FromEmployee -> ToEmployee

Donc, je suggère de rejoindre dans 4 requêtes et unioning les résultats. Quelque chose comme (en supposant que vous après de et aux noms aux fins de l'exemple):

SELECT from.name from_name, to.name to_name
FROM Person from, PersonData pd, Person to
WHERE from.Id = pd.FromPersonId
AND to.Id = pd.ToPersonId
UNION
SELECT from.name from_name, to.name to_name
FROM Person from, PersonData pd, Employee to
WHERE from.Id = pd.FromPersonId
AND to.Id = pd.ToEmployeeId
UNION
... (you get the picture)

+0

Mes tables ont plus de 25 colonnes et j'ai besoin de beaucoup de données, y a-t-il une autre approche que l'union? Existe-t-il un moyen de joindre distinctement la personne et l'employé à PersonData? – VoodooChild

1

Parce que vous ne l'avez pas vous posté schéma que SQL DDL, je vais avoir des problèmes pour voir comment ces tables peuvent travailler entraine toi. Voici ma tentative:

Il semblerait raisonnable d'envisager qu'un employé doit être une personne, si c'est assez facile (deviner les types de données et les règles de domaine):

CREATE TABLE NaturalPersons 
(
PersonId INTEGER NOT NULL UNIQUE 
); 

CREATE TABLE Employees 
(
PersonId INTEGER NOT NULL UNIQUE 
    REFERENCES NaturalPersons (PersonId), 
EmployeeID CHAR(3) NOT NULL UNIQUE 
    CHECK (EmployeeID LIKE '[A-Z][0-9][0-9]') 
); 

Le nom de la table « persondata » n » t révèlent beaucoup, mais des noms d'éléments de données, il semble que quelque chose est transféré d'une personne/employé à un autre:

CREATE TABLE Transfers 
(
FromPersonId INTEGER 
    REFERENCES NaturalPersons (PersonId), 
FromEmployeeID CHAR(3) 
    REFERENCES Employees (EmployeeID), 
ToPersonId INTEGER 
    REFERENCES NaturalPersons (PersonId), 
ToEmployeeID CHAR(3) 
    REFERENCES Employees (EmployeeID) 
); 

Hmm, toutes NULL colonnes capables signifie que nous ne pouvons pas avoir un PRIMARY KEY mais je me demande s'il y a une clé du tout ...?

Nous ne voulons un type d'ID pour « de » et « à » respectivement:

ALTER TABLE Transfers ADD 
CONSTRAINT only_one_from_ID 
    CHECK (
      (FromPersonId IS NULL AND FromEmployeeID IS NOT NULL) 
      OR 
      (FromPersonId IS NOT NULL AND FromEmployeeID IS NULL) 
     ); 

ALTER TABLE Transfers ADD 
CONSTRAINT only_one_to_ID 
    CHECK (
      (ToPersonId IS NULL AND ToEmployeeID IS NOT NULL) 
      OR 
      (ToPersonId IS NOT NULL AND ToEmployeeID IS NULL) 
     ); 

Nous voulons aussi que une des règles d'affaires « de bon sens » pour empêcher les transferts de et vers la même personne/employé :

ALTER TABLE Transfers ADD 
CONSTRAINT FromPersonId_cannot_be_ToPersonId 
    CHECK (FromPersonId <> ToPersonId); 

ALTER TABLE Transfers ADD 
CONSTRAINT FromEmployeeId_cannot_be_ToEmployeeId 
    CHECK (FromEmployeeId <> ToEmployeeId); 

C'est à peu près le mieux que nous pouvons faire, mais nous avons quelques problèmes:

INSERT INTO NaturalPersons (PersonId) VALUES (1), (2), (3), (4); 
INSERT INTO Employees (PersonId, EmployeeID) VALUES (1, 'A11'), (2, 'B22'); 

-- transfer to same entity - oops!: 
INSERT INTO Transfers (FromPersonId, ToEmployeeID) VALUES (1, 'A11'); 

-- Duplicate transfer - oops!: 
INSERT INTO Transfers (FromEmployeeId, ToPersonID) VALUES (1, 'B1'); -- duplicate 
INSERT INTO Transfers (FromPersonId, ToEmployeeID) VALUES ('A1', 2); -- duplicate 

En d'autres termes, le fait de mélanger PersonId et EmployeeID dans la même table rend difficile l'écriture de règles de données de base.

Si j'ai raison de supposer qu'un employé est une personne, pourquoi ne pas utiliser uniquement PersonID?

Si un employé n'est pas une personne, pouvez-vous poster votre schéma (type de données, contraintes, etc.)?

+0

Merci et +1 pour l'excellente explication que j'espère pouvoir lire plus tard. Mais ma question était juste un exemple et n'impliquait pas vraiment la personne ou l'employé - j'avais besoin de faire quelque chose de similaire avec d'autres anciennes données de l'application mais je dessinais un blanc complet ... – VoodooChild