知识卡片

EXTEND扩展运算符与SQL SELECT-FROM-WHERE模板的局限

普通读书笔记卡

内容

原始关系代数(限制/投影/连接/并/交/差)完全没有计算能力,无法表达类似”把零件 重量从磅换算成克”这种需要算术运算的查询。EXTEND补上了这块能力,精确定义是: 给定关系r及r中没有的属性名X,EXTEND r:{X:=exp}是标题为r的标题加上属性X、 主体由r每个元组添加一个按exp计算出的X属性值构成的关系——结果基数不变、度加1。 和RENAME、其他表达式一样,EXTEND只是表达式,不改变数据库中任何关系变量,可以 自由嵌套。EXTEND暴露出SQL的SELECT-FROM-WHERE模板一个结构性缺陷:查询”重量 大于7000克的零件编号和克重”,Tutorial D可以直接写(EXTEND P:{GMWT:=WEIGHT* 454}) WHERE GMWT>7000(先扩展再限制,扩展出来的属性可以立刻在WHERE里用), 但等价的原始SQL写法SELECT PNO,WEIGHT*454 AS GMWT FROM P WHERE GMWT>7000 在标准SQL里编译失败——因为WHERE子句作用于FROM子句的结果,此时表P还没有GMWT 这一列,SELECT子句才是真正引入GMWT的地方,但SELECT-FROM-WHERE模板强制要求 WHERE只能作用在FROM结果上、SELECT必须放在最后一步。这暴露了一个更普遍的问题: 关系代数因为[[关系代数的闭包性质]]支持运算以任意方式组合和嵌套(先扩展、再 限制、再连接、再限制……顺序随意),而SQL固定的SELECT-FROM-WHERE三段式模板 把查询硬性限定为”积→限制→若干投影/扩展/更名的组合”这一种固定顺序,很多查询 其实并不天然符合这个模式,只能靠嵌套子查询(FROM (SELECT... AS GMWT FROM P) AS TEMP WHERE TEMP.GMWT>7000)来绕过这个限制——这也解释了为什么SQL的FROM 子句里嵌套子查询必须强制加一个AS别名(哪怕这个别名从未被引用),因为语法上 它定义的是一个区间变元(range variable),这个声明步骤本身无法省略。

参考来源

- 位置:《SQL与关系数据库理论——如何编写健壮的SQL代码》第7章"SQL和关系代数 II:附加运算符"7.3节"扩展"(源文件:OEBPS/text00076.html) - 结论依据:原文明确"关系变量P在数据库中并未改变!EXTEND并不是SQL风格的 ALTER TABLE……SQL的SELECT-FROM-WHERE模版强制WHERE子句只能应用于FROM子句 而非SELECT子句的结果……很多查询并不符合这个模式……GMWT是'最终结果'的列名; 表P没有这个列,所以WHERE子句自然不会知道,表达式自然会在编译期失败"。 - 原始内容:关系变量P在数据库中并未改变!EXTEND并不是SQL风格的ALTER TABLE ……SQL的SELECT-FROM-WHERE模版强制WHERE子句只能应用于FROM子句而非SELECT 子句的结果……很多查询并不符合这个模式。