sql查询帮助 - 如何正确加入?

时间:2010-06-29 06:55:13

标签: sql sybase data-migration

假设我有一个表“PersonData”,其中有4列是

FromPersonId,FromEmployeeId,ToPersonId,ToEmployeeId

任何记录只包含一个From **和只有一个To **,另外两个列为null。此外,FromPersonIdToPersonId属于“人员”表,FromEmployeeIdToEmployeeId属于“员工”表。

我的问题是:如何正确地将PersonData与Person和Employee表连接?

请注意我已经尝试了许多不同的方法但是当我对PersonData进行计数时,我在进行连接时会得到不同的结果(即它显示的内容比PersonData中的更多)...

我应该如何加入?我应该为每个FromPersonId和ToPersonId为Person做一个,为Employee做类似的吗? (怀疑是这种情况)......

谢谢,

巫毒

3 个答案:

答案 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?

如果员工不是某个人,您可以发布您的架构(数据类型,约束等)吗?