以编程方式确定SQL中所需的一系列JOIN语句

时间:2014-05-16 22:33:41

标签: sql database algorithm foreign-keys

在关于参照完整性和包含依赖性的标准数据库理论中,它提到了一种PSPACE算法,用于获取例如已知的列表。外键和主键关系加上候选关系,并确定候选关系是否在逻辑上隐含在已知列表中。该算法的非确定性版本在this book [pdf]的算法9.1.6中给出,但没有任何明确的确定性版本(我猜测这个想法不是以某种方式手动使用Savitch' ; s找到该算法的定理。)

一个相关的问题是如何以编程方式向数据库系统询问如下问题:

给定查询1的结果集和查询2的结果集,是否有一个已知的预先存在的主/外键依赖关系链,它允许我将两个结果集连接在一起(可能需要额外的列,将来自关键关系的派生链。)

我特意在Postgres,MSSQL或MySQL的上下文中思考如何以编程方式实际向数据库询问此信息。

我可以查询sp_helpsp_fkeys存储过程,但是我不清楚如何从目标表中提供一组列和一组目标表中的列,并直接询问数据库是否可以从sp_fkeys之类的输出中推导出一种将表格相互连接的方法。

如果有已知的算法,我自己也愿意(甚至开心)自己编写代码(基于上面提到的定理,至少数学算法是存在的,即使它已经存在)不直接成为数据库系统的一部分。)

我的应用程序是使用维护不良的模式来摄取各种各样的表,并在模式发现阶段进行一些元编程,这样就不需要成为人在环来尝试手动搜索链关键关系可能意味着两个给定表的连接方式。

假设我的数据库只是这三个表:

TableA

| a_key1  | a_key2  | a_value |
+---------+---------+---------+
|       1 |   'foo' |     300 |
|       2 |   'bar' |     400 |

TableB

| b_key1  | b_key2     | b_value |
+---------+------------+---------+
|   'foo' | 2012-12-01 |   'Bob' |
|   'bar' | 2012-12-02 |   'Joe' |


TableC

| c_key1     | c_key2  | c_value |
+------------+---------+---------+
| 2012-12-01 |     100 |     3.4 |
| 2012-12-02 |     200 |     2.7 |

并且假设b_key1a_key2的外键,c_key1b_key2的外键,而"键是#34}。每个表的列一起构成主键。表格是否规范化是不重要的(例如,b_key1可以识别TableA中的一行,即使TableA表面上有一个2元组对于它的关键 - 这是不重要的,经常发生在你继承的表中。)

然后在这种情况下,只要提前知道关键关系,我们就知道以下连接是"支持" (在外键系统下,数据类型和值范围必须有意义):

select A.*, c.c_value
from TableA A
join TableB B
    on A.a_key2 = B.b_key1
join Table C
    on B.b_key2 = C.c_key1

因此,如果一个人通过两个单独的查询来到数据库:

select *
from TableA

select c_key1, c_value
from TableC

那么数据库系统应该能够推断出使这两者对齐的查询所需的连接(如外键所暗示的,而不是使它们对齐的其他任意方式)。

我的问题是:在主要的SQL兼容的RDBMS中是否已存在生成一系列必需连接的搜索功能?

可以想象遵循所讨论的想法in this answer然后将元数据吸收到其他编程语言中,将其解构为关键关系的一种图形,然后使用已知的图形路径查找算法来解决问题。但是任何自制的实现都会充满错误,而且算法很容易被编写成指数级慢的问题。通过询问数据库系统中是否存在这种情况,我只是尝试利用已完成的工作来实现智能和数据库感知的实现(如果已完成该工作)。

3 个答案:

答案 0 :(得分:2)

让输入查询集为Q,并假设这些查询中的每一个都从单个表中选择列的子集。我假设,当从Q中的表t加到Q外的表时,我们只想考虑那些可以从查询中实际存在的列形成的FK;但是当从Q外的表连接到Q外的另一个表时,我们可以使用这两个表之间定义的任何FK。

在这种情况下,我建议您真正想知道的是,如果有一个唯一连接集将生成所有输入查询的组合列集。这可以有效地测试:

  1. 形成图表G,其中V = {all tables}且E = {(u,v)|从u到v或v到u}存在FK关系,并且附加的限制是Q中的表上的边缘只能使用相应输入查询中存在的列。
  2. 在G。
  3. 上建立跨越森林F.
  4. 如果Q中的任何一对表出现在F的不同组件中,那么我们就知道没有满足我们目标的查询,我们可以停止。
  5. 否则,至少有一个这样的查询,涉及包含Q中所有表的唯一组件X中的部分或全部表。
  6. 要摆脱无意义的连接,删除X中不在Q的某个表中的路径中的所有边到Q中的某个其他表(例如,通过反复“啃掉”所有的边缘到Q之外的某个表,直到不能再这样做了。)
  7. 对于保留在这个新的较小树X中的每个边e:
    1. 在G中创建V(X)的诱导子图的副本X_e,并从X_e中删除边e。
    2. 从X_e。
    3. 创建生成林F_e
    4. 如果F_e由单个组件组成,这只能意味着在Q中连接表格的第二种(即不同的)方式可避免边缘e,因此我们可以停止。
  8. 如果我们到达这一点,那么X中的每个边e都是必要的,我们可以得出结论,X隐含的连接集是从输入查询集Q生成列集的唯一方法。

答案 1 :(得分:0)

任何两个表都可以加入。 (连接的谓词是其操作数的谓词的结合。)

所以你写的很多内容都没有意义。建议您寻求对您的问题进行描述,而不是涉及两个表是否可以加入“方式”。也许,对于操作数的给定约束没有暗示的表达式是否存在可能的约束和/或在给定操作数约束的情况下,对于表达式有什么约束。 (包括可能/推断的FD,MVD,JD和表达式的候选键,或者包含依赖关系或表达式之间的FK。)(Nb,您不需要将表达式限制为连接。例如,可能是一个表子类型另一个。)

答案 2 :(得分:0)

在我看来,你似乎在询问(/理论规则基础)的机制,即任意查询结果之间包含依赖性满意度的推断。

多年来我一直在研究关于关系理论的一切,我从来没有看到任何与该描述相符的东西,所以如果我对这个问题的理解是正确的,那么我的猜测是你的机会很小。 / p>