在 MS Access 中加入 3 个或更多表而不重复条目

Posted

技术标签:

【中文标题】在 MS Access 中加入 3 个或更多表而不重复条目【英文标题】:Joining 3 or more tables without duplicating entries in MS Access 【发布时间】:2018-03-12 12:19:55 【问题描述】:

我目前正在练习我的访问技能,希望对以下问题提供任何帮助。

问题是我正在尝试将 3 个表合并为一个。我将其中一个用作主表(事实表),而其他 2 个表有关于该事实的额外信息,但是信息相同但来自不同的来源。您可以在下面看到一个示例(我仍在弄清楚***,所以我很抱歉造型不佳)

事实表

Name     Age    Gender      
Nordon   21     male

额外信息

Name     Skills         Level
Nordon   Programming    Good
Nordon   Singing        Poor
Nordon   Drawing        Good

ExtraInfo_2

Name     Skills         Level
Nordon   Programming    Good
Nordon   Singing        Good
Nordon   Drawing        Poor

当我尝试在 Access 中使用 Inner Join 执行语句时,我得到如下信息:

结果

Name    Age   Gender    Skills_1      Skills_2     Level_1  Level_2
Nordon  21    male      programming   programming  Good     Good
Nordon  21    male      programming   Singing      Good     Good
Nordon  21    male      programming   Drawing      Good     Poor
Nordon  21    male      Singing       programming  Poor     Good
Nordon  21    male      Singing       Singing      Poor     Good
Nordon  21    male      Singing       Drawing      Poor     Poor

基本上它是将表 1 中的技能映射到表 2 中的每个技能。我期待的是这样的:

结果

Name    Age   Gender    Skills_1      Skills_2     Level_1  Level_2
Nordon  21    male      programming   programming  Good     Good
Nordon  21    male      Singing       Singing      Poor     Good
Nordon  21    male      Drawing       Drawing      Good     Poor

基本上,我想检查不一致之处,但我会自己做。有时,表 Skills_1 和 Skills_2 的每个事实的条目数量也不同。有没有办法解决这个问题?

感谢所有帮助!

【问题讨论】:

还不能添加评论。 This 可能会有所帮助。 我也在看,下面提到了,谢谢! 【参考方案1】:

有很多不同的方法可以做到这一点,但使用INNER JOINs 我猜你只是没有在技能名称上包含两个额外信息表之间的链接?在这种情况下,这样的事情应该可以工作:

SELECT
    f.Name,
    f.Age,
    f.Gender,
    ei1.Skills AS Skills_1,
    ei2.Skills AS Skills_2,
    ei1.Level AS Level_1,
    ei2.Level AS Level_2
FROM
    Fact f
    INNER JOIN ExtraInfo ei1 ON ei1.Name = f.Name
    INNER JOIN ExtraInfo_2 ei2 ON ei2.Name = f.Name AND ei2.Skills = ei1.Skills

如果您在 Extra Info 表中存在潜在的空白,那么您将需要改用 LEFT JOINs,这变得更加棘手,因为在 ExtraInfo_2 与 ExtraInfo 相关的地方,连接条件将停止工作。在这种情况下,您需要使用子查询,所以像这样:

SELECT
    f.Name,
    f.Age,
    f.Gender,
    ei1.Skills AS Skills_1,
    ei2.Skills AS Skills_2,
    ei1.Level AS Level_1,
    ei2.Level AS Level_2
FROM
    ((Fact AS f
    LEFT JOIN (
        SELECT Name, Skills FROM ExtraInfo
        UNION
        SELECT Name, Skills FROM ExtraInfo_2) AS q ON q.Name = f.Name))
    LEFT JOIN ExtraInfo AS ei1 ON ei1.Name = f.Name AND ei1.Skills = q.Skills)
    LEFT JOIN ExtraInfo_2 AS ei2 ON ei2.Name = f.Name AND ei2.Skills = q.Skills

(MS Access 的语法可能不是 100%,但应该接近这个?)

如果您的数据确实如其所见,而您有时只是在“额外信息”中为某些人提供了更多行,那应该没问题。

【讨论】:

嘿,理查德,我真的很感谢您的长而完整的回答!我试过了,我不断收到以下错误:“查询表达式'q.Name = f.Name LEFT JOIN ExtraInfo ei1 ON ei1.Name = f.Name'中的语法错误(缺少运算符)。”你是否偶然知道问题?如果我跳过最后两个左连接,我将获得正确数量的技能,但它们不是每个来源(每个表)。 是的,我感觉 Access 不喜欢那种语法,我会四处寻找,看看能不能找到一个副本在某个地方旋转... 如果您有时间找到一些东西,那将是完美的,非常感谢!顺便说一句,你的回答很棒,谢谢!到目前为止,我只是尝试了不同的连接变体(左或内)但是我一直得到错误的映射 我猜这可能是很多事情,可能是因为 Name 是保留字,或者可能是 Access 需要 AS 语句的事实(所以我将此添加到我上面的回答)?我找到了一个与此类似的示例的链接,所以这可能值得检查吗? dba.stackexchange.com/questions/73659/… 在 MS Access 中,多个 JOIN 子句需要在配对表周围加上括号。【参考方案2】:

也许你可以试试这样的:

SELECT t4.Name, t4.Age, t4.Gender, t4.Skills AS Skills_1, t4.Level AS Level_1, ei2.Skills AS Skills_2, ei2.Level AS Level_2 FROM ( SELECT t3.Name, t3.Age, t3.Gender, ei1.Skills, ei1.Level, t2.Skills AS SkillsAll FROM ( SELECT t1.*, t2.Skills FROM Fact t1 INNER JOIN ( SELECT Name,Skills FROM ExtraInfo UNION SELECT Name,Skills FROM ExtraInfo_2 ) t2 ON t1.Name=t2.Name ) t3 LEFT JOIN ExtraInfo ei1 ON t3.Name=ei1.Name AND t3.Skills=ei1.Skills ) t4 LEFT JOIN ExtraInfo_2 ei2 ON t4.SkillsAll=ei2.Skills AND t4.Name=ei2.Name;

【讨论】:

嘿R. Verbelis,我已经尝试过你的方法,但是这样你可能会错过一些技能,以防表3的技能比表2多,对吧?【参考方案3】:

考虑对相关计数子查询进行匹配,但会占用大表:

SELECT agg1.Name, agg1.Age, agg1.Gender, agg1.Skills AS 1, agg1.Level AS Level_1,
       agg2.Skills AS 2, agg2.Level AS Level_2
FROM 
   (SELECT f.Name, f.Age, f.Gender, e1.Skills, e1.Level, 
           (SELECT Count(*) FROM ExtraInfo sub
            WHERE sub.Name = e1.Name AND sub.Skills <= e1.Skills) As rank
      FROM Fact f INNER JOIN ExtraInfo e1 ON f.Name = e1.Name
   )  AS agg1 

LEFT JOIN 
  (SELECT f.Name, f.Age, f.Gender, e2.Skills, e2.Level,
          (SELECT Count(*) FROM ExtraInfo sub
           WHERE sub.Name = e2.Name AND sub.Skills <= e2.Skills) As rank
      FROM Fact f INNER JOIN ExtraInfo2 e2 ON f.Name = e2.Name
   )  AS agg2 ON (agg1.rank = agg2.rank) AND (agg1.Name = agg2.Name);


-- Name    Age  Gender  Skills_1     Level_1    Skills_2      Level_2
-- Nordon   21  male    Drawing      Good       Drawing       Poor
-- Nordon   21  male    Singing      Poor       Singing       Good
-- Nordon   21  male    Programming  Good       Programming   Good

【讨论】:

哇,Parfait,你能解释一下这个基于计数的匹配吗?如果我错了,请纠正我,但如果使用内部连接,你会错过一些技能,以防其中一张表有更多条目。 子查询计算 ExtraInfoExtraInfo_2 表中每个不同 Skill 的排名 1、2、3按字母顺序。是的,以前的解决方案会遗漏大桌子的技能。请参阅使用LEFT JOIN 编辑以保留第二个表的所有行(如果第一个也可以这么大,请查看完全外连接)。 基本上你需要为你的输出调整技能的顺序,而不是技能本身。现在考虑您的需求,这是一个数据库设计问题。考虑结合 ExtraInfo 并从那里运行报告。 可能是一个愚蠢的问题,但你的排名是基于什么?你有计数,所以你计算它出现了多少次?我还是有点新,我可能在这里迷路了 如技能名称字母顺序所述。子查询和外部查询之间存在关联:sub.Skills &lt;= e1.Skills。您正在计算有多少行按字母顺序低于当前行的技能名称。

以上是关于在 MS Access 中加入 3 个或更多表而不重复条目的主要内容,如果未能解决你的问题,请参考以下文章

如何使用内部/外部组合在 Access 中加入 4 个以上的表?

在 MS ACCESS 中加入两个不同的计数查询

如何在 PL/SQL 中连接两个表而不创建新表

将完整的 ADO 记录集插入现有的 ACCESS 表而不使用循环

MS Access 表单以更新多个表而无需子表单

如何在查询中加入 MS-SQL 和 MySQL 表?