需要在第三张桌子中加入 2 张桌子及其 FK

Posted

技术标签:

【中文标题】需要在第三张桌子中加入 2 张桌子及其 FK【英文标题】:Required to join 2 tables with their FKs in a 3rd table 【发布时间】:2014-07-13 09:55:07 【问题描述】:

所以基本上我正在关注一个教程问题,该问题问我以下问题。我不太确定如何加入不包含其他 FK 的 2 个表,它们(即他们的两个 FK)位于第三个表中。 我可以得到一些帮助/解释吗?

我的答案

SELECT Forest.Fo_name, Species.Sp_name, Species.Sp_woodtype
FROM Forest
INNER JOIN Species
ON Tree.Tr_species=Tree.Tr_forest
WHERE Fo_loc='ARTIC'
ORDER BY Fo_name, Sp_name

“对于在编码为“ARTIC”的区域中发现的森林,列出森林名称和物种名称以及在其中发现的物种木材类型。消除所有重复项并按森林名称和物种名称排序输出”

物种表

+--------------+------------------+------+--------------------------------+
| Field        | Type             |  Key | Glossary                       |
+--------------+------------------+------+--------------------------------+
| sp_name      | C(10)            |  PK  | Species Name                   |
| sp_woodtype  | C(10)            |      | Wood Yielded by tree           |
| sp_maxht     |  I               |      | Max. Height                    |
+--------------+------------------+------+--------------------------------+

森林表

+--------------+------------------+------+--------------------------------+
| Field        | Type             |  Key | Glossary                       |
+--------------+------------------+------+--------------------------------+
| Fo_name      | C(10)            |  PK  | Forest Name                    |
| Fo_size      |   I              |      | Forest Area                    |
| Fo_loc       | C(10)            |      | Geographical Area              |
| Fo_comp      | C(10)            |      | Forest Owner                   |
+--------------+------------------+------+--------------------------------+

树形表

+--------------+------------------+------+---------------------------------------------+
| Field        | Type             |  Key | Glossary                                    |
+--------------+------------------+------+---------------------------------------------+
| Tr_species   | C(10)            |  FK  | (FK  of species.sp_name                     |
| Tr_forest    | C(10)            |  FK  | (FK of forest.fo_name                       |
| Tr_numb      |   I              |  PK  | Sequence number                             |
| Tr_planted   | Date             |      | Date of planting                            | 
| Tr_loc       | C(10)            |      | Forest quadrant                             |
| Tr_parent    |   I              |  FK  | (FK of tree.numb) procreating tree reference|
+--------------+------------------+------+---------------------------------------------+

C(10) & I 分别代表字符 (10) & Integer

【问题讨论】:

Tree.Tr_species=Tree.Tr_forest ?只见树木不见森林? 【参考方案1】:

Tree 表是 Forest 表和 Species 表之间的连接。将其视为两个步骤:

1)从Forest表开始,加入Tree表(从Forest.Fo_nameTree.Tr_forest

2) 现在知道树,加入Species 表(从Tree.speciesSpecies.sp_name

我会像这样编写最终查询:

SELECT Forest.Fo_name, Species.Sp_name, Species.Sp_woodtype
FROM Forest
JOIN Tree ON Forest.Fo_name=Tree.Tr_forest
JOIN Species ON Tree.species=Species.sp_name
WHERE Fo_loc='ARTIC'
ORDER BY Fo_name, Sp_name

【讨论】:

【参考方案2】:

连接表不需要外键!

因此,当它们之间没有 FK 时如何连接表的答案是只需加入它们

真正的问题是我们如何选择加入哪些表(或以任何其他方式组合)?

报表和表格

每个基表都带有一个谓词——由列名参数化的语句模板。表值是使其谓词成为真正的命题--语句的行。

// species [name] yields [woodtype] and has max height [maxht]
Species(name,woodtype,maxht)
// forest [name] has area [size] in area [loc] and owner [comp]
Forest(name,size,loc,comp)
// tree group [numb] is of species [species] in forest [forest] and was planted in [planted] in quadrant [loc] on date [date] with parent tree group [parent]
Tree(species,forest,numb,planted,loc,parent)

查询也有谓词。它的值也是使其谓词为真的行。它的谓词是根据它的FROMWHERE 和其他子句建立起来的。表别名将表值命名为与其基表类似,但列以别名为前缀。所以它的谓词是它的基表使用别名前缀列的谓词。

Species s

保持满足的行

species [s.name] yields [s.woodtype] and has max height [s.maxht]

CROSS & INNER JOIN 在谓词之间放置 AND; UNION 在它们之间放置 OR;除了在条件中插入 AND NOT 和 ON & WHERE AND; SELECT 重命名、添加和删除列。 (等其他运营商。)所以

Species s CROSS JOIN Forest f

保存行

    species [s.name] yields [s.woodtype] and has max height [s.maxht]
AND forest [f.name] has area [f.size] in area [f.loc] and owner [f.comp]

(无论约束是什么!)如果您只希望上面的行具有以其木材类型命名的森林,那么您只需通过 ... WHERE f.name=s.woodtype 添加一个条件,因为这会使值成为满足 ... AND f.name=s.woodtype 的行。

对于在编码为“北极”的地区发现的森林,请列出在其中发现的森林名称和物种名称以及物种木材类型。消除所有重复项并按森林名称和物种名称对输出进行排序。

这是返回的行要满足的一个很大的非正式谓词。如果我们尝试仅使用给定的谓词加上 AND、OR 和 AND NOT(等)来重写它,那么我们只能通过 ANDing 所有三个给定的谓词(因此,基表的 JOIN名称)并添加 AND Forest.loc='ARCTIC'(因此,ONWHERE 条件)。

FK(等)和查询(非)

PK 和 FK 是完整性约束的特殊情况。给定谓词和可能出现的情况,只能出现一些数据库值。这就是完整性约束所描述的。他们让 DBMS 将不应该出现的数据库值排除在外。 (另外,优化查询执行。)因为名称在 Species 中是唯一的,所以我们将其声明为键。森林名称和树麻木同上。因为 Tree 中的物种是 Species 中的名称,而名称是 Species 的键,所以我们声明 FK Tree.species->Species.name。森林和父母同上。与启用联接无关。 (尽管它们暗示查询结果也满足某些约束。)

查询约束是什么并不重要。如果存在由于业务规则或树或物种谓词不同而未显示为任何物种名称值的树物种值,则将没有 FK Tree.species->Species.name。但是每个查询将继续返回满足其谓词以基表谓词表示的行。 (由于可能的业务情况或谓词不同,输入行可能不同,因此输出行也可能不同。)

什么决定了查询 SQL

因此,我们如何选择要连接(或以任何其他方式组合)哪些表的答案是,我们适当地安排基表名称、JOIN、UNION、EXCEPT 和 WHERE(等),以给出谓词为的查询表达式我们希望我们的行满足的那个。这通常被认为是非正式的,可以通过感觉来完成,但现在您知道 SQL 与自然语言的联系了。并且约束是无关紧要的。

注意:前面假设我们没有从查询中返回重复项。之所以在关系模型中表中没有重复,是因为上面的表操作符和逻辑连接符的对应关系成立。但是 SQL 表可以有重复项。 SQL 不同于关系模型的地方(在很多方面),那里的查询变得不那么合乎逻辑。

Re joins following foreign keysRe choosing tablesIs there any rule of thumb to construct SQL query from a human-readable description?

【讨论】:

【参考方案3】:

您可以进行多个连接。将树表链接到您的主表森林,然后链接物种表:

SELECT 
Forest.Fo_name, 
Species.Sp_name, 
Species.Sp_woodtype

FROM 
Forest
INNER JOIN Tree ON Tree.Tr_forest=Forest.Fo_name
INNER JOIN Species ON Tree.Tr_species = Species.sp_name

WHERE 
Fo_loc='ARTIC'

ORDER BY Fo_name, Sp_name

【讨论】:

【参考方案4】:

试试 SQL 99 方法

      SELECT DISTINCT F.Fo_name, S.Sp_name, Sp_woodtype
      FROM Forest F, Species S, Tree T
      WHERE F.Fo_name = T.Tr_Forest 
      AND S.Sp_name = Tr_species
      AND f.Fo_loc = 'ARCTIC';

A F S 是用于使 SQL 更短、更整洁的别名。

DISTINCT 将删除重复项。

【讨论】:

【参考方案5】:

ON 条件应该比较不同表中的列。

然后你只需一步一步加入每个表。

SELECT DISTINCT Fo_name, Sp_name, Sp_woodtype
FROM Forest AS f
INNER JOIN Tree AS t ON t.Tr_forest = f.Fo_name
INNER JOIN Species AS s ON t.Tr_speecies = s.Sp_name
WHERE f.Fo_loc = 'ARCTIC'
ORDER BY Fo_name, Sp_name

【讨论】:

【参考方案6】:
SELECT Forest.Fo_name, Species.Sp_name, Species.Sp_woodtype
    FROM Forest
        INNER JOIN Tree 
            INNER JOIN Species ON Species.sp_name = Tree.Tr_species
        ON Forest.Fo_name=Tree.Tr_forest
WHERE Fo_loc='ARTIC'
ORDER BY Fo_name, Sp_name

【讨论】:

以上是关于需要在第三张桌子中加入 2 张桌子及其 FK的主要内容,如果未能解决你的问题,请参考以下文章

rails 3,加入更多三张桌子

三张桌子在同一个窗口,iPad

如何在 SQL SERVER 中加入我的条件?

如何在 laravel eloquent 中加入三个表?

按我的第二张桌子的计数(*)排序需要很长时间

如何从多个表中加入 SELECT,其中 SELECTS 基于不同的条件?