知识卡片
属性名依赖问题与程序内外部数据独立定义的正确方案
内容
关系代数运算符高度依赖恰当的属性命名(如自然连接靠同名属性建立对应),这带来
一个看似脆弱的疑虑:如果给某个关系变量新增一个属性、恰好和另一个关系变量已有
的属性同名,会不会破坏原有查询?书中先澄清:这不是设计漏洞——同名属性被要求
必须同类型(形式上说就是”同一个属性”),不同类型的属性必须用不同名字,这条
约束本身不构成实质限制,因为[[类型推理规则与RENAME运算符的必要性]]中的RENAME
运算符总能在需要时化解命名冲突。真正的问题根源在别处:当今大多数SQL系统里,
应用程序访问数据库靠调用级接口或嵌入式SQL,这意味着数据库定义实际上并不是
程序类型结构的一部分——一句常被引用的话是”如果数据库定义真的是程序类型结构
的一部分,那么大部分数据库应用程序的编程错误都会显式为类型错误”,但现实中
它们不是,这个缺陷可以追溯到上世纪60年代对”数据独立性”的一个部分性误解:
当时认为要实现数据独立性,只需要把数据库定义和程序分离即可;但真正需要的其实
是两份独立的定义——一份存在于程序内部(代表开发者对数据库的认知,同时支持
编译期查询检查),一份存在于程序外部(代表”如现实一般”的真实数据库结构),
后期如果外部定义需要变更,只要调整两者之间的映射关系,就能在完全不改动程序
代码的前提下维持逻辑独立性(书中用假设的”公共表”CREATE PUBLIC TABLE语法
和显式映射定义演示了这套机制该怎样工作,如果SP表后来新增SNAME列,只需要
调整映射本身,应用程序完全不用变化)。可惜当今SQL产品并未真正实现这套双层
定义机制,S NATURAL JOIN SP或SELECT * FROM S这类表达式因此确实会遇到
“脆弱”问题;退而求其次的实用对策仍然是[[SQL列命名与位置依赖关系化使用SQL的
实践规则]]里已给出的策略:为每张基表定义遵循统一命名规则的视图,程序只对
视图而不对底层基表编写查询,基表结构变化时只需调整视图定义。