假设我有一个表“PersonData”,其中有4列是
FromPersonId,FromEmployeeId,ToPersonId,ToEmployeeId
任何记录只包含一个From **和只有一个To **,另外两个列为null。此外,FromPersonId
和ToPersonId
属于“人员”表,FromEmployeeId
和ToEmployeeId
属于“员工”表。
我的问题是:如何正确地将PersonData与Person和Employee表连接?
请注意我已经尝试了许多不同的方法但是当我对PersonData进行计数时,我在进行连接时会得到不同的结果(即它显示的内容比PersonData中的更多)...
我应该如何加入?我应该为每个FromPersonId和ToPersonId为Person做一个,为Employee做类似的吗? (怀疑是这种情况)......
谢谢,
巫毒
答案 0 :(得分:2)
看起来有四种可能性:
FromPerson - > TOPERSON
FromPerson - > ToEmployee
FromEmployee - > TOPERSON
FromEmployee - > ToEmployee
所以,我建议加入4个查询并将结果联合起来。类似的东西(假设你为了示例的目的而在from和to名称之后):
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)
答案 1 :(得分:1)
好的,所以听起来问题是如果你在FromPersonID = PersonID和ToPersonId = PersonID上加入Person,你会得到PersonData中每条记录的2条记录。
解决这个问题的方法是加入2个别名的PersonData副本,这样你就可以将结果附加到同一行。类似的东西:
Select * from PersonData
LEFT JOIN Person p1 on p1.PersonID = FromPersonID
LEFT JOIN Person p2 on p2.PersonID = ToPersonID
并且基本上对来往员工字段
执行相同操作答案 2 :(得分:1)
因为您还没有将模式发布为SQL DDL,所以我在查看这些表在实践中如何工作时遇到了问题。这是我的尝试:
员工必须是一个人,这似乎是一个公平的假设,所以这很容易(猜测数据类型和域规则):
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]')
);
表名'PersonData'没有透露太多信息,但从数据元素名称看来,某个人/员工正在转移到另一个人:
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)
);
嗯,所有NULL
能列都意味着我们不能拥有PRIMARY KEY
,但我想知道是否有钥匙......?
我们只需要一种类型的ID分别用于'from'和'to':
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)
);
我们还需要一个“常识”业务规则来阻止来自同一个人/员工的转移:
ALTER TABLE Transfers ADD
CONSTRAINT FromPersonId_cannot_be_ToPersonId
CHECK (FromPersonId <> ToPersonId);
ALTER TABLE Transfers ADD
CONSTRAINT FromEmployeeId_cannot_be_ToEmployeeId
CHECK (FromEmployeeId <> ToEmployeeId);
这是我们能做的最好的事情,但我们遇到了一些问题:
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
换句话说,在同一个表中混合使用PersonId和EmployeeID会使编写基本数据规则变得困难。
如果我认为员工是一个人是正确的,为什么不仅仅使用PersonID?
如果员工不是某个人,您可以发布您的架构(数据类型,约束等)吗?