表的“三角关系”中的 SQL 查询

Posted

技术标签:

【中文标题】表的“三角关系”中的 SQL 查询【英文标题】:SQL Query from "Triangular Relation" of Tables 【发布时间】:2020-12-08 11:27:37 【问题描述】:

我很难在 SQL 中找到一个看似简单的方法。我正在使用 MS Access,但我想这并不重要。 我的数据结构如下所示:

所以tblA 有“产品”,tblB 有“组件”,tblC 有“模块”。这显然只是一个例子。 tblA(“产品”)与tblB(“组件”)有 m:n 关系,即一个产品由一些组件组成,组件可以属于许多产品。 tblB ("Component") 与 tblC ("Modules") 有 m:n 关系,即一个组件由模块组成,而模块可以属于许多组件。现在的转折是,我在tblAtblC 之间也有一个 m:n 关系,即产品和模块的映射。这是因为组件的“配置”可能会根据其所针对的产品而有所不同。因此,对于“产品 1”,“组件 2”需要由“模块 1”和“模块 2”组成,而对于“产品 2”,“组件 2”只是“模块 2”。

我想要一个这样的结果

|Product|Component|Module|
|-------|---------|------|
|Prod1  |C1       |      |
|Prod1  |C2       |      |
|Prod1  |C2       |M1    |
|Prod1  |C2       |M2    |
|Prod2  |C2       |      |
|Prod2  |C2       |M2    |
|Prod2  |C3       |      |
|Prod2  |C3       |M3    |

tblA 中有“Prod1”和“Prod2”; tblB 中的“C1”、“C2”、“C3”和 tblC 中的“M1”、“M2”、“M3”。关系是

所以本质上我想要一个包含 Product、Component、Module 的表格,其中包含 Product+ 的所有组合

现在使用 SQL 查询

SELECT tblA.Product,
       tblB.Component,
       tblC.Module
FROM tblC
INNER JOIN ((tblA
             INNER JOIN (tblB
                         INNER JOIN mapAB ON tblB.[Component] = mapAB.[Component]) ON tblA.[Product] = mapAB.[Product])
            INNER JOIN mapAC ON tblA.Product = mapAC.Product) ON tblC.Module = mapAC.Module;

我明白了

这是可以理解的,但不是我想要的。我尝试先进行tblAtblB 的连接,然后将其与左连接(或右连接)与tblBtblC 的连接结合起来,但这会产生“不支持的连接操作”错误。

关于如何解决这个问题的任何想法?

【问题讨论】:

【参考方案1】:

查看您的关系,您没有使用主键来建立一对多关系,而是使用数据字段。

在这种情况下,这个查询应该适合你:

SELECT tblA.Product, mapAC.Module, MapAB.Component
FROM (tblA LEFT JOIN mapAC ON tblA.Product = mapAC.Product) LEFT JOIN MapAB ON tblA.Product = MapAB.Product;

在这种情况下,所有其他表格都只是提供信息,因为您已经拥有表格 MapABMapAC 中的可用数据。

我建议在你的关系中使用主键。

更新: 您的查询可以通过三种途径获取您需要的数据:

    tblA -> mapAB + mapAC tblA -> mapAB -> tblB -> mapBC -> tblC tblA -> mapAC -> tblC -> mapBC -> tblB

根据您要遵循的查询的数据路径,外观会有所不同。

Route 2 查询:

SELECT tblA.Product, MapAB.Component, mapBC.Module
FROM (((tblA LEFT JOIN MapAB ON tblA.Product = MapAB.Product) LEFT JOIN tblB ON MapAB.Component = tblB.Component) LEFT JOIN mapBC ON tblB.Component = mapBC.Component) LEFT JOIN tblC ON mapBC.Module = tblC.Module;

Route 3 查询:

SELECT tblA.Product, mapAC.Module, mapBC.Component
FROM (((tblA LEFT JOIN mapAC ON tblA.Product = mapAC.Product) LEFT JOIN tblC ON mapAC.Module = tblC.Module) LEFT JOIN mapBC ON tblC.Module = mapBC.Module) LEFT JOIN tblB ON mapBC.Component = tblB.Component;

【讨论】:

感谢您的建议。我认为这是朝着正确的方向发展。但它还没有给出我想要的结果。您的查询会产生组件 (tblB) 和模块 (tblC) 的所有组合,而不仅仅是 mapAC 允许的组合。可能是因为 mapAC 或多或少被第一个 LEFT JOIN 忽略了?在主键上你是对的。这主要是为了说明目的。 请分享你想走哪条数据路线,查看更新答案 我提供的查询,遵循路线1 从第一眼看,Route 2 将是我想要的路径。我有点尝试这样做(tblaA LEFT(tblAB LEFT tblB))LEFT(mapBC LEFT tblC)。但要么我的语法错误,要么这不是下一步连接操作的正确方法,我还没有让它工作。 查看您的数据/结构,以及所需的结果,我认为您无法使用此结构实现结果【参考方案2】:

好的,根据 jbud 的建议,我能够像这样构建所需的结果:

qryProdModComp = SELECT tblA.Product, mapBC.Component, mapAC.Module
FROM (tblA LEFT JOIN mapAC ON tblA.Product = mapAC.Product) LEFT JOIN mapBC ON mapAC.Module = mapBC.Module;

几乎已经给了我想要的东西

但是请注意,缺少 Prod1 和 C1 的行(没有直接链接 Mx)。 为了得到这个,我添加了

qrySingleC = SELECT tblB.Component AS Component
FROM   tblB
       LEFT JOIN mapBC
       ON tblB.Component = mapBC.Component
WHERE  mapBC.Component Is Null
UNION
SELECT mapBC.Component
FROM   tblB
       RIGHT JOIN mapBC
       ON tblB.Component = mapBC.Component
WHERE  tblB.Component Is Null

qryProdCompOnly = SELECT tblA.Product, mapAB.Component, NULL AS Module
FROM tblA INNER JOIN ( qrySingleC INNER JOIN mapAB ON qrySingleC.Component = mapAB.Component  ) ON tblA.Product = mapAB.Product;

qryOverall = SELECT Product,Component,Module FROM qryProdCompMod UNION SELECT Product,Component,Module FROM qryProdCompOnly;

给了

得到与我原来帖子中要求的完全相同的结果实际上看起来还是更干净一些

qryProdCompOnly2 = SELECT tblA.Product, mapAB.Component, NULL AS Module
FROM tblA INNER JOIN mapAB ON tblA.Product = mapAB.Product;

qryOverall = SELECT Product,Component,Module FROM qryProdCompMod UNION SELECT Product,Component,Module FROM qryProdCompOnly2;

给予

【讨论】:

使用tblA, tblB, tblC and mapABC 简化您的结构不是更容易吗?这样您就可以控制产品、组件和模块组合。 mapABC 将在结果中包含您需要的字段,因此不需要复杂/计算的查询。 是的,我想这会更容易,我目前正在考虑这样做。这将对我的数据模型的其他部分产生影响,我仍然需要权衡为此所做的努力与该主题所获得的简单性......无论如何,我只是想分享这种方法,因为它回答了我最初的问题。非常感谢您的帮助!

以上是关于表的“三角关系”中的 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章

查询中的错误 - 缺少表的 FROM 子句条目 - SQL

SQL中,如何查询存在一个表的字段而不在另一个表的字段中的数据记录?

sql如何在多个表中查询一个表的全部列

怎样用SQL查询一个表的所有字段

SQL查询字段名

多表的慢速 SQL 查询