本节书摘来华章计算机《SQL与关系数据库理论——如何编写健壮的SQL代码》一书中的第2章 ,第2.1节 C. J. Date 著 单世民 何英昊 许侃 译 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
2.9 SQL中的行类型和表类型
再来用一下2.5节“标量类型vs.非标量类型”中定义元组变量的例子:
VAR STV TUPLE { STATUS INTEGER , SNO CHAR , CITY CHAR , SNAME CHAR } ;
你可能还记得,表达式TUPLE{}是对TUPLE类型生成器的调用。SQL有对应的ROW类型生成器(尽管SQL将其命名为类型构造器(type constructor))。下面是一个对前述Tutorial D示例的SQL类比:
DECLARE SRV /* SQL row variable */
ROW ( SNO VARCHAR(5) ,
SNAME VARCHAR(25) ,
STATUS INTEGER ,
CITY VARCHAR(20) ) ;
然而,与元组不同,SQL中的行对其分量采用自左至右的排序;注19就以此为例,同样的四个分量可以构成24(=4×3×2×1)种不同的行类型(!)。
SQL也支持行赋值。考虑如下Tutorial D元组赋值:
STV := TUPLE FROM ( S WHERE SNO = 'S1' ) ;
下面是类比的SQL行赋值:
SET SRV = ( S WHERE SNO = 'S1' ) ;
右侧表达式是一个行子查询(从语法上讲是一个表表达式,但实际上作为一个行表达式)。这也是SQL中没有什么能显式地对应Tutorial D的TUPLE FROM的原因所在。(参见2.7节“SQL中的类型检查和型转”中对于子查询和型转的讨论)。
在SQL的UPDATE语句(参见第3章)中实际上也涉及了行赋值。.
再来说表。有趣的是,SQL根本没有一个真正的TABLE类型生成器(或像SQL中的类型构造器)!也就是说,SQL没有什么能直接类比于前文中,描述的RELATION类型生成器。然而,它有一个机制(CREATE TABLE)来定义本应被称为TABLE变量的东西。比如,回想一下2.5节“标量类型vs.非标量类型”中的定义:
VAR S BASE
RELATION { SNO CHAR , SNAME CHAR , STATUS INTEGER , CITY CHAR }
KEY { SNO } ;
下面是SQL的类比:
CREATE TABLE S
( SNO VARCHAR(5) NOT NULL ,
SNAME VARCHAR(25) NOT NULL ,
STATUS INTEGER NOT NULL ,
CITY VARCHAR(20) NOT NULL ,
UNIQUE ( SNO ) ) ;
要小心,本例中没有语言标记序列(sequence of linguistic tokens )能标记为“对TABLE类型构造器的调用”。(在你意识到定义供应商某一完整性的约束UNIQUE(SNO)声明不必列定义,而是几乎可以出现在任何地方(比如,SNO和SNAME列定义之间)之后,这一事实会更加明显。对于单个列定义中同样定义完整性约束的NOT NULL声明就更不必说了。)事实上,在这个意义上可以认为变量S在SQL中具有任何类型,而不管是什么类型它都只不过是“行包”(bag of rows),而当前所讨论行的类型是ROW (S`
NO VARCHAR (5),SNAME VARCHAR (25),STATUS INTEGER ,CITY VARCHAR (20))。
即便如此,我同时应该说明的是:SQL确实支持所谓的“类型化表”(typed tables)。不过,这个词不是很贴切,因为如果TT是一个定义为“T类型”的“类型化表”,那么TT就不是T类型的,并且它的行也不是!更重要的是,你应该尽量避开这样的表,因为它们与SQL对指针(pointer)的支持紧密相关,而指针是在关系模型中被明确禁止的。注20事实上,如果某个表的某列取值是指向另一“目标”表数据行的指针的话,那么这个表就不可能代表关系模型意义下的关系。注21然而,如刚才说的,SQL中不幸地允许此种表存在;指针称为引用值(reference values),包含指针的列则是REF类型(REF type)的。坦白地说,SQL中为什么要包括这些特性完全让人搞不懂;从有用的功能性上来看没什么事是非用它们不可的,事实上不用它们甚至可以做得更好。强烈建议:别用它们以及任何与其相关的特性。
旁注:为了避免可能的混淆,我要说明一下,SQL实际上在两个完全不同的意义下使用术语“参照(referencing)”。一个就像上面描述的那样。另外一个意义(也是更早出现的意义)和外键有关;一行中的一个外键取值被认为是“参照”包含对应目标键值的行。然而要注意,外键可不是指针!——这两个概念之间有多处逻辑差异,尤其是外键指向的是行(也就是行值),而指针是地址,因此按定义指向的是变量。(第1章中提到过,变量是“有空间位置的(have location)”,而值没有空间位置,也没有地址)。