【发布时间】:2014-09-13 03:45:33
【问题描述】:
通常您会在两个表的外键之后连接它们,以便始终可以找到 RHS 表中的行。添加连接不会影响受查询影响的行数。例如
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)
现在,假设你在这两个表中设置了一些数据,你可以从a中获取一定数量的行:
select x from a
在外键之后向 b 添加连接不会改变这一点:
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 是否是保留键的类型,它可能会添加额外的列但不会改变返回的行数,或者是否有其他影响。随着时间的推移,我制定了一个我主要坚持的编码约定:
- 如果是保留键的连接,请使用
join - 如果要过滤行,请将过滤条件放在
where子句中 - 如果想要更多行,有时
cross join笛卡尔积是最清晰的方法
这些通常只是样式问题,因为您通常可以将谓词放入 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 静态检查器工具来完成这项工作,并且可以使用特殊的注释语法而不是新的关键字。检查器工具需要访问数据库模式才能查看存在哪些外键,但它不需要实际执行查询。
有什么东西可以满足我的需求吗?我正在使用 MSSQL 2008 R2。 (微软 SQL Server 为迂腐)
【问题讨论】:
-
如果我正确理解了这个问题,一致的命名约定可能有助于缓解部分或全部这些问题。如果
Customers与Orders在Customers.CustomerID = Orders.CustomerID上加入,你可以一眼看出条件是有道理的,而加入Customers.CategoryID=Orders.ProductID显然看起来不对。 -
连接“成功”或“失败”到底是什么意思?因为你可以加入任何两个表。
-
@philipxy,抱歉我的问题不够清楚,我已经编辑了一下。
-
@Andriy M,是的,命名约定可以提供帮助。但是,除非你是一个不会出错的编程机器人,否则要跟踪事情并不容易——我犯了太多错误,不能仅靠我自己的细心。例如,如果您有来自
customers的查询,那么添加join orders on customers.customerid = orders.customerid是不是通过这种措施进行的安全更改 - 因为它现在将排除没有订单的客户,并为有两个订单的客户。所以我不能在不影响查询语义的情况下添加或删除这样的连接。 (反之亦然。)
标签: sql-server join sql-server-2008-r2 foreign-keys static-code-analysis