-
毕竟是语义化的查询,一切还是以语义为准。
-
“由内而外”进行查询。也就是说,从修饰词(不仅仅是定语,还有可能是一些别的修饰)开始,一层一层深入到最终的对象。
-
至少(at least)一般使用连接运算。目前我能想到的,大概有两个理由:
- “至少”表明了一种存在性,而连接运算表明了这种存在性(因为如果不存在,是不会出现在连接运算的结果里的)。
- “至少”隐含了对多于一个操作数(也就是不止一张表)进行操作的意思,因为“至少”是一个修饰词。而且,“至少”往往是被操作的一方。比如,查询至少订购了一个价格为$0.5的商品的顾客,就隐含了对商品、顾客、订单三张表的操作。
-
不(not)、从不(never)等否定词一般使用减运算。因为,否定一般是从某个整体中排除掉一些不符合内容的过程,正好和减运算的语义相吻合。(这有点哲学意味,否定之否定?)
请注意选择正确的“被减数”,否则会导致无谓的精度丢失。
-
只(only)一般使用不等运算符(< >)。
这同时意味着“只”会和where一起出现,因为这是一个对范围进行限制的过程;不过,用where来进行范围的处理是很自然的,也没什么可说的。
因为,“只”所包含的范围很狭窄,用where是不能保证完全过滤的。比如,考虑这样的一个场景:
检索只参加过’p2’号项目的职工的姓名。
这里,如果我们用where,就会过滤出参加过p2项目的职工,但并不一定是只参加过p2项目的职工。我们需要用更强的条件去约束,也就是排除掉所有参加过别的项目的职工。这一点上在数学上似乎叫“正难则反”。
-
全部(all)一般使用除运算。
“全部”这个词具有误导性,因为全部的含义太过于宽泛,以至于很多句子即使加上了“全部”这个词,也不会严重影响语义。但这会给我们的判断带来负担。
-
既…又…(both,或者译作同时?)一般使用交运算。
为什么不用and运算符?因为根据第一范式规则,表里每一列不能有重复字段,所以行内的每一列上只可能有一个简单值,所以表里的每一个值不能既是a又是b。这也就是说,
A = 'a' and A = 'b'
是永远不可能成立的,只能用交运算进行拼接。值得一提的是,交运算(包括并运算等集合上的运算)必须在两张兼容的表间进行。
-
值对(pairs,或者叫二元组?)、三元组(triples)一般使用笛卡尔积。因为笛卡尔积可以将两张表强行关联在一起(哪怕两张表并没有相同的字段;在这一点上,连接运算就做不到)。
通过笛卡尔积扩展表,再进行筛选和投影运算,是很常用的。
-
一对多的关系一般也使用笛卡尔积,形如
A × A' where A.a = A'.a and A.target < > A'.target
。这一条可能不怎么直观,我们不妨看一个例子:检索拥有两个或两个以上家属的职工的姓名。
在这里我们可以看到,员工和家属的关系是一对多的,也就是一个员工对应多个家属。所以,在这里用笛卡尔积就很自然了。
事实上,我觉得一对多就是pairs和triples的一个变种。如果将上面的场景变成检索
( 员工, 家属, 家属... )
这样的元组,是不是就一样了呢。 -
最值有两种实现,一种是利用差运算,一种是利用除运算。其实从语义上来说也是很好理解的,以最大值为例,前一种实现是从集合中“去掉”所有不够大的值,后一种实现则是找到比“所有”都大的值。并且,这个场景也可以看做是一对多关系的一个变种(一个最值对应多个非最值)。
这是第一种实现:
A[a] - (A × A' where A'.a > A.a)[A.a]
这是第二种实现:
(A × A' where A'.a >= A.a)[A'.a, A.a] ÷ A[a]
-
其实所有的连接都可以用笛卡尔积实现。从本质上来说,连接就是一个一对一或者一对多的关系,都可以用N元组来刻画。比如,想要连接两张表,除了用连接运算之外,也可以这样(当然,这样会有冗余;不过一般都会用投影来缩小范围):
A × B where A.a = B.a
事实上,SQL语句中的SELECT就是这么实现的。
关系代数的语义化查询
最新推荐文章于 2024-09-20 14:38:20 发布