zl程序教程

您现在的位置是:首页 >  工具

当前栏目

《SQL与关系数据库理论——如何编写健壮的SQL代码》一一2.5 标量类型vs.非标量类型

vsSQL代码 如何 类型 编写 理论 2.5
2023-09-11 14:19:16 时间

本节书摘来华章计算机《SQL与关系数据库理论——如何编写健壮的SQL代码》一书中的第2章 ,第2.5节 C. J. Date 著 单世民 何英昊 许侃 译 更多章节内容可以访问云栖社区“华章计算机”公众号查看。

2.5 标量类型vs.非标量类型

通常,都会认为类型不是标量的就是非标量的。换言之,如果一个类型没有用户可见的分量,那么它就是标量的;否则它就是非标量的。某个类型T的值、变量、属性、运算符、参数及表达式是否是标量的,取决于类型T本身是否是标量的。例如:

整数类型是标量类型,因此,整数类型的值、变量等也都是标量的,即它们没有用户可见分量。 元组和关系类型是非标量的(相关的用户可见分量是对应的属性)。因此,元组和关系值、变量等也都是非标量的。

必须强调,这些概念是相当不严格的。实际上,我们已经看到数据值原子性的概念本就没有什么绝对的含义,那么“标量”本身也只不过是同一概念的另一名称罢了。因此,在任何正式意义上,关系模型都不会依赖于标量与非标量的区别。然而,在本书中要非正式地依赖它。我发现它直观上非常有用。具体说,对于既不是元组也不是关系的类型,使用术语标量;而对于元组或关系类型,使用术语非标量。注12
旁注:你有时会听到另一个表示“标量”的术语是封装(encapsulation)。然而要小心,这个术语也被(尤其在对象上下文中)用来指对代码和数据(更准确地是运算符定义和数据表示定义)的物理捆绑或打包。但是若使用了后面这种意义,就混淆了模型和实现,显然用户并不关心也不必关心代码和数据到底是物理绑定在一起的还是分离的。
我们来看一个例子。下面是Tutorial D对于基关系变量 S(supplier)的定义。注意,为了简化,我将所有的属性都定义为某种系统定义类型:

1. VAR S BASE

2. RELATION { SNO CHAR , SNAME CHAR , STATUS INTEGER , CITY CHAR }

3. KEY { SNO } ;

解释:
第1行中的关键字VAR表示此句为一个变量的定义;S是变量的名称,关键字BASE特别指出变量是一个基关系变量。
第2行指定变量的类型。关键字RELATION说明它是一个关系类型。此行的剩余部分指定构成对应关系标题的属性集合(在第1章中,一个属性定义为一个“属性-名称”/“类型-名称”对,并且在标题中没有两个属性具有相同的属性名称)。当然,类型是非标量类型。属性的顺序并不重要。
第3行定义{SNO}是这个关系变量的(候选)键。
事实上,这个例子也讲解了另一要点,即下述类型是一个生成式类型的示例。

RELATION { SNO CHAR , SNAME CHAR , STATUS INTEGER , CITY CHAR }

一个生成式类型是通过调用某些类型生成器(type generator)获得的类型(此例中,类型生成器就是RELATION)。你可以认为一个类型生成器是一种特殊类型的运算符;它之所以特殊是因为:(a)它返回一个类型而不是一个值;(b)它在编译期被调用而不是在运行时被调用。比如,大部分编程语言都支持名为ARRAY的类型生成器,可以让用户定义各种特定的数组类型。然而,我们现在关心的类型生成器是TUPLE和RELATION。下面是一个包含TUPLE类型生成器的示例:

VAR STV /* 元组变量 */

 TUPLE { STATUS INTEGER , SNO CHAR , CITY CHAR , SNAME CHAR } ;

在任何时刻变量STV的取值都是一个标题与关系变量S的标题相同的元组(我特意指定了不同的属性顺序,就是为了说明次序并不重要)。注13因此,我们可以设想一个代码片段:(a)从关系变量S当前取值中抽取一个“一-元组”关系(可能这个关系就包含一个针对供应商S1的元组);(b)从那个“一-元组”关系中抽取单一的元组;(c)将抽取出的元组赋值给变量STV。在Tutorial D中:

STV := TUPLE FROM ( S WHERE SNO = S1 ) ;

重点:我可不想让你在这里产生误解。尽管某些存取suppliers-and-parts数据库的应用程序需要STV这样的变量,但在数据库内部不可以出现这样的变量。一个关系数据库只包含一种变量,即关系变量(relvars)。换句话说,关系变量是关系数据库中唯一允许存在的变量类型。(后面提到——关系变量是关系数据库中允许存在的唯一变量类型——构成了信息原理(Information Principle)。附录A中将进行更详细的说明)。
另外,要特别注意的是(如前例所示)一个元组t和一个仅仅包含元组t的关系r是存在逻辑差异的。尤其是,它们属于不同类型——t是某个元组类型而r是某个关系类型(尽管这些类型确实有一样的属性标题,或者说有相同的属性)。
最后,以下内容为其他要点:

尽管元组和关系类型都有用户可见分量(即它们的属性),但并不是说这些分量也必须进行同样的物理存储。实际上,元组及关系的物理表示应该对用户是掩藏的,就好像标量值一样。(参考第1章中对于物理数据独立性的讨论。) 类似于标量类型,元组和关系类型肯定需要与其关联的选择器运算符(字面值是特例)。下一章将详细说明。不过,它们并不需要THE_运算符;替代的,它们有对相应属性进行存取的运算符,这些运算符的角色相当于THE_运算符之于标量类型。 元组和关系类型还需要赋值和相等比较运算符。本节已经给出了元组赋值的示例;下一章会对其他的运算符进行详细说明。
一行SQL代码能做什么?(下) 最近在知乎上看到一个问题:一行代码可以做什么?答题者数万计,都是一些非常“高端”的操作,就在想一行SQL代码能做什么呢?