《SQL与关系数据库理论——如何编写健壮的SQL代码》一2.4 类型是什么

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

2.4 类型是什么

现在开始,我要用“类型”代替“域”了。那么到底类型是什么?实质上,它就是已命名的、有限的值集合——某种特定类型的所有可能取值。比如,所有可能的整数,所有可能的字符串,所有可能的供应商编号,所有可能的XML文档,或者所有可能的带有某一标题的关系等等。简要地说:

  • 我们所关心的类型都是有限的,因为我们使用的是计算机,这是根据定义就已经确定是有限的了(就像在本章先前在类型部分提到过的那样)。
  • 还要注意限定词“已命名的”:不同名称的类型是不同类型。
    另外:
  • 每个值总是某种类型的值——事实上,就是某一种类型的,除非有对类型继承的支持。类型继承的概念超出了本书的范围。注意:因为没有值能够同时属于两种类型,所以类型根据定义是互斥(不重叠)的。不过,我或许需要对此简要叙述一下。正像本章的一位评审所说的,恒温动物类型和四足动物类型不是重叠的么?它们确实重叠,不过我要说的是如果类型之间重叠,那么就有一堆原因促使我们探究类型继承——实际上,是探究所谓的多继承。因为那些原因(实际上就是继承的整个主题)与我们所处的上下文无关,所以我不打算在此书中对其进行讨论。
  • 每个变量、每个属性、每个返回一个结果的运算符,以及每个运算符的每个参数都要声明为某种类型。注8也就是说,如果变量V声明为类型T则表示-每个可被合法赋值给V的值v都应是类型为T的值。
  • 每个表达式都表示某个值,并且也因此是属于某种类型的,即,当前正在讨论的那个值的类型,也就是表达式最外层运算符返回值的类型,( “最外层”指的是最后执行的运算符)。

比如,下面表达式的类型

(a/b)+(x-y)

就是“+”号运算符所声明的类型(不管它到底是什么)。

参数尤其要声明为某种类型,这一事实涉及一个我提到过但是还未正式讨论的议题:对于每个类型,都有与类型关联、用于运算该类型值和该类型变量的一系列运算符。也就是说,“运算符Op与类型T相关联”的准确含义是“运算符Op具有一个声明为类型T的参数”。注9比如,整数有常用的算术运算符;日期和时间有特殊的日历算术运算符;XML文件有所谓的“XPath”和“XQuery”运算符;关系有关系代数运算符;每个类型都有赋值(“:=”)和相等比较(“=”)运算符。因而,任何提供正规类型支持(这里的正规类型支持当然包括允许用户定义类型)的系统都必须也提供手段, 以便让用户可以自定义运算符,因为没有运算符的类型是没有用的。注意:你一定会想到,用户定义运算符可以与系统定义类型相关,也可以与用户定义类型相关(当然也可以与两者皆相关)。
现在可以看到,根据定义,某个确定的类型的值和变量只能使用与该类型相关的运算符进行运算。比如,对于INTEGER这一系统定义类型:
系统提供赋值运算符“:=”用于将整数值赋值给整型变量。
系统提供了整数字面值的书写格式。(不过除了简单字面值之外系统没有提供其他任何选择器运算符,也没有提供任何THE_运算符,因为这样的运算符对于INTEGER这样的系统定义类型而言并不需要)。

  • 系统为比较整数值提供了比较运算符“=” “≠”“<”等等。
  • 系统为执行针对整数值的算术运算提供了算术运算符“+”“*”等等。
  • 系统没有为针对整数值的字符串运算提供“||”(连接)、SUBSTR(子串)- 等字符串运算符;换句话说,系统不支持针对整数的字符串运算。

相反,对于用户定义类型SNO(仍假定它是用户定义的),我们一定要定义必要的选择器和THE_运算符,而且我们还要定义赋值(“:=”)和比较运算符(“=”“≠”,也许还有“<”等)。然而,我们或许不用定义“+” “*”等运算符。这意味着针对供应商编号的算术运算是不被支持的(对两个供应商编号进行加或乘是什么含义呢?)。
根据前面说过的内容,现在应该可以明确,在定义一个新类型时至少要包括下述所有工作:

  1. 为类型定义名称(这是很显然的)。
  2. 定义构成类型的值。第8章将详细讨论此内容。
  3. 为类型的值定义隐藏的物理表示。如前所述,这是个实现问题而非模型议题,此书不会进一步讨论。
  4. 为选择或者指定该类型的取值定义一个选择器运算符。
  5. 定义应用于该类型取值和该类型变量的运算符——尤其要包括赋值(“:=”)、相等比较(“=”)以及THE_运算符(见下文)。
  6. 为返回结果的运算符定义所返回结果的类型(见下文)。
    观察4~6可知,它们在一起隐含地说明了系统确切知道什么表达式是合法的,同时也知道这些合法表达式结果的类型。

比如,假设我们有一个用户定义类型POINT,表现为两维空间中的几何点。那么,下面给出的就是Tutorial D中对于REFLECT运算符的定义,即对于确定的笛卡尔坐标为(x,y)的点P,返回笛卡尔坐标为(-x,-y)的“反射”或“相反”点(可以用SQL,但是SQL中的运算符定义包含大量在此处不研究的细节):

  1. OPERATOR REFLECT ( P POINT ) RETURNS POINT ;
  2. RETURN POINT ( - THE_X ( P ) , - THE_Y ( P ) ) ;
  3. END OPERATOR ;
    解释:
  • 第1行显示了REFLECT运算符,使用一个参数P,参数类型为POINT,返回值类型也为POINT(所以运算符的声明类型为POINT)。
  • 第2行是运算符实现代码。它由一个单一RETURN语句组成。要返回的值是调用POINT选择器获得的点;而对POINT选择器的调用有两个实参,对应于要返回的点的X坐标和Y坐标。每个实参均通过THE_运算符调用方式进行定义;这些调用生成对应于形参P的实参的X坐标及Y坐标,并且对坐标取反来得到期望的结果。注10
  • 第3行标志定义的结束。

虽然本节大部分的讨论都是基于用户定义类型进行的,但是类似的情况也适用于系统定义类型。唯一的不同在于系统定义类型是由系统而不是用户提供的。例如,如果INTEGER是一个系统定义类型,那么它就是由系统来定义名称、合法整型值、后台的表现形式,以及(如我们所见的)定义对应的文字格式和运算符(“:=” “=” “+”)等等(当然,用户也可以定义附加的运算符)。
我多次提到过选择器(selector)运算符,但我却从未说过(至少没有明确说过)选择器(更准确的说,选择器调用)实际上就是对更为熟知的字面值(literal)概念的概括。注11我想用这个注解说明所有的字面值都是选择器调用,但并非所有的选择器调用都是字面值(实际上,只有选择器调用中所有的参数都是字面值的情况下,这个选择器调用才是字面值的)。例如, POINT(X,Y)和POINT(1.0,2.5)都是选择器调用,但只有后者是一个POINT字面值。它遵循了每个类型有(必须有) 一个关联的字面值书写格式的要求。为完整起见,应该加一条:要求每个类型的每个值都必须用某种字面值表示。

上一篇:报错:RuntimeError: cuDNN error: CUDNN_STATUS_EXECUTION_FAILED


下一篇:转:安装了anaconda不需要安装CUDA和cuDNN