所以基本上我正在按照下面问我的教程问题。我不太确定如何加入2个不包含其他FK的表,它们(即它们的两个FK)都位于第3个表中。 我可以得到一些帮助/解释吗?
我的回答
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)&我代表角色(10)&整数分别为
答案 0 :(得分: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)
查询也有谓词。它的值也是使其谓词成立的行。它的谓词是根据FROM
,WHERE
和其他子句构建的。表别名将表值命名为其基表,但列的前缀为别名。所以它的谓词是使用别名前缀列的基表的谓词。
Species s
保持满足
的行species [s.name] yields [s.woodtype] and has max height [s.maxht]
CROSS& INNER JOIN在谓词之间放置AND; UNION在他们之间放置OR; EXCEPT插入AND NOT和ON&在哪里和在一个条件; 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
添加条件,因为这会使值成为满足{{1 }}
对于在编号为“ARCTIC”的地区发现的森林,列出森林名称&物种名称和物种木材类型。消除任何重复项并按林名和物种名称对输出进行排序。
这是一个很大的非正式谓词,返回的行要满足。如果我们尝试仅使用我们已经给出的谓词加上AND,OR和AND NOT(等)来重写它,那么我们只能通过... AND f.name=s.woodtype
所有三个给定谓词来执行它(因此,AND
基表名称)并添加JOIN
(因此,AND Forest.loc='ARCTIC'
或ON
条件)。
FK(等)和查询(不是)
PKs和FK是完整性约束的特例。鉴于谓词和可能出现的情况,只会出现一些数据库值。这就是完整性约束所描述的。他们让DBMS保留不应出现的数据库值。 (另外,优化查询执行。)因为名称在Species中是唯一的,所以我们将其声明为密钥。森林名称和树麻木同上。因为Tree中的物种是物种中的名称,而名称是物种的关键,我们声明FK Tree.species-> Species.name。同样适用于森林和父母。与启用连接无关。 (虽然它们暗示查询结果也满足某些约束。)
查询约束是什么并不重要。如果由于业务规则或树或物种谓词不同而存在未显示为任何物种名称值的树种值,则不存在FK Tree.species-> Species.name。但是每个查询将继续返回满足其谓词的行,如基表谓词所表示的那样。 (由于可能的业务情况或谓词不同,输入行可能不同,因此输出行可能不同。)
决定查询SQL的内容
因此,我们如何选择要连接的表(或以任何其他方式组合)的答案是我们根据需要安排基表名,JOIN,UNION,EXCEPT和WHERE(等)以提供其谓词为的谓词表达式我们希望我们的行满足的那个。这通常被教导为非正式的感觉,但现在你知道SQL与自然语言的联系。约束是无关紧要的。
注意:前面假设我们不会从查询中返回任何重复项。在关系模型中表中没有重复的原因是表操作符和逻辑连接符之间的上述对应关系成立。但是,SQL表可能有重复项。 SQL与关系模型(在很多方面)的区别在于,查询变得更少(字面上)逻辑。
Is there any rule of thumb to construct SQL query from a human-readable description?
答案 1 :(得分:1)
你可以做多个连接。将树表链接到主表林,然后链接物种表:
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
答案 2 :(得分:1)
Tree
表是Forest表和Species表之间的连接。把它想象成两个步骤:
1)从Forest表开始,加入Tree
表(从Forest.Fo_name
到Tree.Tr_forest
)
2)现在树已知,加入Species
表(从Tree.species
到Species.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
答案 3 :(得分:0)
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
答案 4 :(得分:0)
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
答案 5 :(得分:0)
尝试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';
F S是用于使SQL更短且更整洁的别名。
DISTINCT将删除重复项。