create table a (x int not null primary key) create table b (x int not null primary key,y int not null) alter table a add foreign key (x) references b (x)
现在,假设您在这两个表中设置了一些数据,您可以从以下位置获取一定数量的行:
select x from a
在外键后面添加连接不会改变:
select a.x from a join b on a.x = b.x
但是,对于一般的连接来说,情况并非如此,这可能会过滤掉某些行或(通过笛卡尔积)添加更多:
select a.x from a join b on a.x = b.x and b.y != 42 -- probably gives fewer rows select a.x from a join b on a.x != b.y -- probably gives more rows
在读取sql代码时,没有明显的方法来判断连接是否是保持键的类型,它可能会添加额外的列但不会更改返回的行数,或者是否具有其他效果.随着时间的推移,我开发了一个编码约定,我大多坚持:
>如果是密钥保留连接,请使用join
>如果想要过滤行,请将过滤条件放在where子句中
>如果想要更多行,有时候笛卡尔积的交叉连接是最清晰的方法
这些通常只是样式问题,因为您通常可以将谓词放入join子句或where子句中.
我的问题
在编译查询时,是否有某种方法可以使数据库服务器静态检查这些密钥保留连接?我知道查询优化器已经知道外键上的连接总是会在外键指向的表中找到一行.但我想在我的sql代码中标记它以造福人类读者.例如,假设新语法fkjoin用于外键后的连接.那么下面的sql片段会给出错误:
a fkjoin b on a.x = b.x -- OK a fkjoin b on a.x = b.x and b.y = 42 -- "Error,join can fail due to extra predicate" a fkjoin b on a.x = b.y -- "Error,no foreign key from a.x to b.y"
在编写sql时,以及稍后返回读取时,这对我来说是一个有用的检查.我理解并接受更改数据库中的外键会改变sql在此方案下的合法性 – 对我来说,这是一个理想的结果,因为如果必要的FK不再存在,那么查询的密钥保留语义就不是更长的保证,我想了解它.
可能有一些外部sql静态检查工具可以完成工作,可以使用特殊注释语法而不是新关键字.检查器工具需要访问数据库模式以查看存在的外键,但不需要实际执行查询.
解决方法
基表具有“含义”或“谓词(表达式)”,它是DBA给出的填充(命名)空白语句.该语句的空白名称是表的列.填补空白以成为关于世界的真正主张的行将列入表格.填补空白以排斥世界的行将被排除在外.即表格包含满足其陈述的行.您不能在不知道其语句的情况下将基表设置为某个值,观察世界并将适当的行放入表中.你不可能从基表知道这个世界,除非知道它的陈述并将当前行命题变为真实和缺席 – 行命题是错误的.即你需要它的声明来使用数据库.
请注意,表声明的典型语法看起来像是其语句的简写:
-- employee [eid] is named [name] and lives at [address] in ... EMPLOYEE(eid,name,address,...)
您可以通过在其他语句之间/周围放置逻辑运算符AND,OR,AND NOT,EXISTS name,AND condition等来创建更大的语句.如果通过转换将语句转换为关系/ sql表达式
>表格的名称声明
>和加入
>或UNION
>而不是除了/减去
> EXISTS C,… […]选择除C,… FROM之外的所有列…
> AND条件为ON / WHERE条件
>对SUBSETOF的影响
> IFF =
然后你得到一个关系表达式,计算使语句成立的行. (UNION& EXCEPT / MINUS的参数需要相同的列.)因此,正如每个表都保存满足其语句的行一样,查询表达式保存满足其语句的行.你无法从查询结果中了解世界,除非知道它的陈述并将其当前行命题变为真实和缺席 – 行命题是错误的.即你需要它的陈述来撰写或解释一个查询. (观察不管有什么约束,这都是正确的.)
这是关系模型的基础:表表达式计算满足相应语句的行. (就sql而言,它实际上是不合逻辑的.)
例如:如果表T保存使语句T(…,T.Ci,…)为真的行,而表U保存使语句U(…,U.Cj,…)为真的行然后表T JOIN U保存使语句T(…,…)和U(…,…)为真的行.这是JOIN的语义,对于使用数据库很重要.你总是可以加入,一个连接总是有意义,它总是它的操作数的意义的AND.是否有任何表恰好将FK用于其他表对于推理更新或查询并不是特别有用. (当您犯错时,DBMS会使用约束.)
约束表达式恰好对应于关于世界的命题,也就是总是真实的陈述,并且同时关于基表的陈述.例如,对于U中的C UNIQUE NOT NULL,以下三个表达式彼此相同:
>外键T(C)参考文献U(C)
> EXTTS C T以外的列(…,C,…)
IMPLIES EXISTS C U以外的列(…,…)
>(SELECT C FROM T)SUBSETOF(从C中选择C)
确实,这意味着SELECT C FROM T JOIN U ON T.C = U.C = SELECT C FROM U,即FK上的连接返回相同数量的行.但那么呢?连接的含义仍然与其参数的功能相同.
特定列集上的特定连接是否涉及外键与理解查询的含义没有密切关系.