当辅助表没有记录时,SQL报告错误

时间:2013-05-14 23:15:32

标签: sql ms-access left-join ms-access-2010

我正在编写一个带有Access 2010后端和VB.NET前端的Family Tree应用程序。 (长篇故事,这里不相关。) 大多数一切都有效,但我需要为一个人的婚姻排序。与在一个家庭中对儿童进行排序一样,我们不能只使用明显的DateOfBirth或DateOfMarriage字段,因为我们并不总是有值。这是我的数据结构的简化快照

People Table                Families Table
- ID                        - ID
- FullName                  - Husband
- DOB (Date of Birth)       - Wife
- DOD (Date of Death)       - DOM (Date of Marriage)

PersonMarriage Table (a linking table)
- Person (foreign key to People)
- Family (foreign key to Families)
- Spouse (foreign key to People)
- Marriage Order (a contrived value to force the order we want)

FamilyChild Table (a linking table)
- Family (foreign key to Families)
- Child  (foreign key to People)
- BirthOrder (a contrived value to force the order we want)

(FWIW,我的出生日期,日期和婚姻是设计的,以便我可以处理像“1862年3月”和“1753年之前”这样的值,但仍然保持可排序性。空字符串表示“未知”)

我正在尝试阅读有关一个人所有婚姻的相关数据,以便我可以使用复杂的比较来提供部分排序。例如,当一个人有两次婚姻,而我们不知道结婚日期时,如果配偶B的孩子在配偶B死后出生,我们可以推断出与配偶B的婚姻是先发生的。

对于每一次婚姻,我想要找回结婚日期,配偶的DOB,配偶的DOD和孩子的DOB。 (任何孩子;我只是用生日来抓住第一个物理记录。)这是一个有时有效的SQL查询:

SELECT PersonMarriage.Family, PersonMarriage.Spouse, DOM, s.DOB, s.DOD,
    (SELECT TOP 1 c.DOB FROM FamilyChild 
        LEFT JOIN People c ON FamilyChild.Child=c.ID 
    WHERE c.DOB<>"" AND FamilyChild.Family=PersonMarriage.Family) as ChildDOB 
FROM Families AS f INNER JOIN 
    (PersonMarriage INNER JOIN People AS s ON PersonMarriage.Spouse = s.ID )
ON f.ID = PersonMarriage.Family 
WHERE PersonMarriage.Person=?

请注意,我在字段列表中使用子查询来查找子项。我确定我需要将子选择子查询移动到FROM子句并使用LEFT JOIN,但我还没想出办法。连接顺序FWIW由Access的查询向导确定,因为对我来说最自然的连接顺序不起作用。

此查询似乎仅在至少有一个婚姻有子女出生日期时才有效。如果婚姻中​​没有一个孩子有出生日期,我会得到“此查询最多可以返回一个结果”的顺序错误。

有什么建议吗?

1 个答案:

答案 0 :(得分:1)

关于错误

  

“此子查询最多可以返回一条记录。”

您的问题源于这样一个事实:如果TOP 1存在“绑定”,则使用ACE / Jet(Access)数据库时,TOP 1查询实际上可能会返回多行。例如,给出[People]数据......

ID  FullName  DOB         DOD
--  --------  ----------  ---
 1  Dave      1967-07-01     
 2  Gertrude  1968-03-21     
 3  Alice     after 1968     
 4  Duncan    after 1987 
 5  Ernest    after 1987     
 6  Richard   after 2003     
 7  Suzy      after 2003     

...查询...

SELECT TOP 1 * FROM [People] ORDER BY [DOB] DESC

...将返回两行:

ID  FullName  DOB         DOD
--  --------  ----------  ---
 7  Suzy      after 2003     
 6  Richard   after 2003

所以,而不是子查询......

(
    SELECT TOP 1 c.DOB 
    FROM FamilyChild LEFT JOIN People c 
            ON FamilyChild.Child=c.ID 
    WHERE c.DOB<>"" AND FamilyChild.Family=PersonMarriage.Family
) as ChildDOB

...尝试使用

(
    SELECT MIN(c.DOB) 
    FROM FamilyChild LEFT JOIN People c 
            ON FamilyChild.Child=c.ID 
    WHERE c.DOB<>"" AND FamilyChild.Family=PersonMarriage.Family
) as ChildDOB