建立数据库的过程包括创建数据库表。在设计数据库时,就应该为应用程序指定好所需的表字段和关系。当以后创建这些表时,再对每个字段的数据类型、标题和默认值,每个表的触发器以及用来建立表间关系的表索引做进一步的选择。本章描述了在开发应用程序时,创建、改进及联接表和索引的过程。这里主要讨论如何使用语言以编程方式来处理表,对于使用界面通过交互方式处理一般性的任务,也作了相应的说明。
本章内容要点:
您可以创建数据库表,也可以创建与数据库无关联的自由表。如果将表放在数据库中,可以为数据库表建立长表名和长字段名。您还能利用数据字典功能来创建数据库表、长字段名、默认字段值、字段级规则和记录级规则以及触发器。
一个 Visual FoxPro 表或 .dbf 文件,能够存在以下两种状态之一:数据库表(与数据库相关联的表),与数据库无关联的自由表。相比之下,数据库表的优点要多一些。当一个表是数据库的一部分时,它就可以具有:
有关将表和数据库关联起来的内容,请参阅第六章“创建数据库”。
数据库表可以具备自由表所没有的属性
您可以使用“表设计器”以交互方式设计和创建表(通过“项目管理器”或“文件”菜单调用“表设计器”),也可以使用语言以编程方式来创建表。本节主要说明以编程方式创建表的方法。有关使用“表设计器”以交互方式创建表的内容,请参阅《用户指南》中的第二章“创建表和索引”。
在编程时,您可以用以下命令创建并编辑表:
用于创建和编辑表的命令
ALTER TABLE | CLOSE TABLES |
CREATE TABLE | DELETE FILE |
REMOVE TABLE | RENAME TABLE |
DROP TABLE |
通过菜单系统、项目管理器或者使用语言,都可以在数据库中创建新表。在创建表时,可以建立长表名和长字段名、默认字段值、字段级和记录级规则以及触发器。
若要创建新的数据库表
– 或者 –
例如,以下代码可以创建一个名为 smalltbl
的表,该表只有一个名为 name
的字段:
OPEN DATABASE Sales
CREATE TABLE smalltbl (name c(50))
新表将自动与创建该表时所打开的数据库相关联。该关联通过存储在表中头记录的后链来定义。
自由表就是不与数据库关联的表。例如,要想保存多个数据库所共享的查找信息,就可以创建一个自由表。
若要创建新的自由表
– 或者 –
例如,以下代码可以创建一个名为 smalltbl
的自由表,该表只有一个名为 name
的字段:
CLOSE DATABASES
CREATE TABLE smalltbl FREE (name c(50))
若创建表时没有打开任何数据库,不必使用关键字“FREE”。
在 Visual FoxPro 中使用 CREATE TABLE 命令时,应指定 .DBF 文件的文件名,此 .DBF 文件用于存储所创建的新表。该文件名同时也是数据库表和自由表的默认表名。表名可以由字母、数字或下划线组成,但表名的第一个字符必须是字母或下划线。
如果是数据库表,则可以指定一个长表名。长表名最多可包含 128 个字符,并且在能使用短文件名的地方就能使用长文件名。如果定义了长表名,当表出现在界面(如“数据库设计器”、“查询设计器”、“视图设计器”以及“浏览”窗口的标题栏)中时,Visual FoxPro 就会显示长表名。
若要给出数据库表的长表名
– 或者 –
例如,以下代码可以创建一个名为 vendintl
的表,并给表命名一个更容易理解的长表名 vendors_international
:
CREATE TABLE vendintl NAME vendors_international (company C(40))
您可以使用“表设计器”重新命名表,或者给没有长表名的表加上一个长表名。例如,在将自由表添加到数据库中时,可以使用“表设计器”为其加上长表名。长表名可以包含字母、数字或下划线,但首字符必须是字母或下划线。在长表名里不能使用空格。
您可通过界面改变数据库表的名称,因为改变的是长名称。若从数据库中移走表,表的文件名恢复原名。自由表没有长名称,只能通过编程方式改名。
若要在数据库中重命名表
若要改变自由表的名称
如果表与数据库相关联,当从数据库中移去表时,可以选择是否进行删除。删除表与从数据库中移去表不同。如果只是从数据库中移去表,但并不想在磁盘中对表做物理删除,请参阅第六章“创建数据库”中的“从数据库中移去表”部分。
若要从磁盘中删除数据库表
– 或者 –
– 或者 –
– 或者 –
注意 若数据库表使用 RENAME 命令,该命令不更新数据库的后链,可能会造成表访问错误。
以下代码可以打开名为 testdata
的数据库,并删除 orditems
表:
OPEN DATABASE testdata
DROP TABLE orditems
若在 REMOVE TABLE 命令中使用 DELETE 字句删除表,同时还会删除相关的 .fpt 备注文件和 .cdx 结构索引文件。
对于自由表,可以通过“项目管理器”或使用 DELETE FILE 命令删除表文件。
若要删除自由表
– 或者 –
例如,如果 sample
是当前表,以下代码可以关闭该表,并在磁盘上删除该文件:
USE
DELETE FILE sample.dbf
在发出 DELETE FILE 命令时,想要删除的文件不能处于打开状态。如果要删除的表有与之相关联的 .fpt 备注或索引文件(.cdx 或 .idx),应确保同时删除了这些文件。例如,如果文件 sample.dbf
有与之相关联的备注文件,可以用以下命令删除这两个文件:
USE
DELETE FILE sample.dbf
DELETE FILE sample.fpt
您可以制作一个表结构的副本,其中包括表的存储过程,触发器表达式以及字段的默认值。制作副本只能通过编程完成,菜单中没有该功能。这一过程不能复制表的内容。
若要复制表
为修改已有的表结构,可使用“表设计器”或 ALTER TABLE。还有一种方法,您可以根据已有表的结构创建一个新表,然后修改新表的结构。
若要复制和编辑表的结构
新表目前是空表。
在浏览表时,可以使用“文件”菜单上的“另存为 HTML”命令,以便将表中的内容另存为 HTML (超文本标记语言)文件。
若要将表另存为 HTML 文件
在创建新表时,您为每个字段指定字段名称,数据类型和字段长度,这些信息决定了在表中数据是如何被标识和保存的;您还可以指定某个字段是否允许 null 值,它在默认时的值,以及它的验证规则,这些信息决定了什么样的值可以出现在某字段中;您还可以设置字段的显示属性,决定当字段加入到表单中时使用什么控件,显示字段内容时采用什么格式,以及标识字段内容的标题。
注释 Visual FoxPro 的表可包括多达 255 个字段。若一个或多个字段可包含 null 值,表可包含的最大字段数减少一个,从 255 到 254。
请在创建新表时指定字段名。自由表的字段名最多可包含 10 个字符,数据库表的字段名最多可包含 128 个字符。如果从数据库中移去一个表(该表变为自由表),那么此表的长字段名将被截短成 10 个字符。
若要给表字段命名
– 或者 –
例如,用以下命令可以创建并打开名为 customer
的表,该表有三个字段:cust_id
、company
和 customer
:
CREATE TABLE customer (cust_id C(6), company C(40), contact C(30))
在前面的示例中,C(6)
表示字段的宽度为 6,而字段的类型为字符型。为表字段选择数据类型的方法将在本节稍后的部分进行讨论。
使用 ALTER TABLE 命令,可在已存在的 customer
表中添加 company
和 contact
字段。
ALTER TABLE customer ;
ADD COLUMN (company C(40), contact C(30))
在创建数据库表时,Visual FoxPro 把表字段的长字段名存储在 .dbc 文件的一个记录中,长名的前 10 个字符同时还作为字段名保存在 .dbf 文件中。
如果长字段名的前 10 个字符在表中不唯一,Visual FoxPro 就取长字段名的前 n 个字符,然后在后面追加顺序标号,共同形成 10 个字符长的字段名。以下是一些长字段名及其转换成长度为 10 个字符后的字段名:
长名 | 短名 |
customer_contact_name | customer_c |
customer_contact_address | customer_2 |
customer_contact_city | customer_3 |
... | ... |
customer_contact_fax | customer11 |
当一个表与数据库相关联时,必须使用长字段名来引用该表中的字段,不能使用长度为 10 个字符的字段名来引用数据库表中的字段。如果将该表从数据库中移去,其长字段名就会丢失,这时必须使用存储在 .DBF 中的、长度为 10 个字符的字段名来引用该表中的字段。
您可以在索引文件中使用长字段名。但是,如果用长字段名创建索引,然后又从数据库中移去包含此长字段名的表,那么索引将无法正常工作。在这种情况下,可以删除索引并用短字段名重新创建索引。有关删除索引的内容,请参阅本章稍后的“删除索引”部分。
除了名称最多可包括 128 个字符外,创建长字段名的规则和创建任何 Visual FoxPro 标识符完全一样。有关命名 Visual FoxPro 标志符的详细内容,请参阅“创建 Visual FoxPro 名称”。
在创建每个表字段的同时,还要为字段所存储的数据选择数据类型。当您选择字段的数据类型时,就是决定了:
提示 对于电话号码、零件编号以及其他不需要用于数学计算的数字,最好选择字符数据类型而非数值数据类型。
若要选择字段的数据类型
– 或者 –
例如,以下命令可以创建并打开 products
表,该表有三个字段:prod_id
、prod_name
和 unit_price
:
CREATE TABLE products (prod_id C(6), prod_name C(40), unit_price Y)
在以上示例中,跟在 unit_price
字段名后面的“Y”说明此字段为货币数据类型。
有关指定数据类型的详细内容,请参阅“数据和字段类型”。
当加入一个字段时,可通过在“表设计器”的索引列中指定升序或降序以快速指定字段的普通索引。创建的索引自动加入索引选项卡列表,并使用字段名作为索引表达式。若要修改索引,可切换到索引选项卡以改变索引名、类型或增加一个过滤器。
在建立新表时,可以指定表字段是否接受 null 值。使用 null 值是为了说明这样一种情况:在字段或记录里的信息目前还无法得到。例如,如果一名雇员的保健津贴或税收状况在填写记录时还不清楚,那么,与其存储一个可能产生歧义的零或空格,则不如在字段中存储 null 值,直到存入有实际意义的信息为止。
若要逐个字段地控制 null 值的输入
当 Null 列被选定时,该字段接受 null 值。
– 或者 –
例如,以下命令可以创建并打开 customer
表,其中的 cust_id
和 company
字段不允许为 null 值,而 contact
字段则允许为 null 值:
CREATE TABLE customer (cust_id C(6) NOT NULL, ;
company C(40) NOT NULL, contact C(30) NULL)
您也可以用 SET NULL ON 命令控制表字段中是否允许 null 值。
若要允许所有表字段都可以为 null 值
– 或者 –
如果使用了 SET NULL ON 命令,在向“表设计器”中添加字段时,Visual FoxPro 会自动为每个表字段选定 NULL 列。如果在使用 CREATE TABLE 命令之前使用 SET NULL 命令,则不必再指定 NULL 或 NOT NULL 子句。例如,用以下代码可以创建表,表中的每个字段都允许为 null 值:
SET NULL ON
CREATE TABLE test (field1 C(6), field2 C(40), field3 Y)
由于 Null 值的存在,对表和索引进行某些操作后,其内容会受到影响。例如,如果用 APPEND FROM 命令把记录从允许使用 null 值的表复制到不允许包含 null 值的表中,所加入的包含 null 值的字段在新表中将被处理成空白、空值或零。
Visual FoxPro 命令如何使用 NULL 值的详细内容,请参阅“处理 Null 值”。
在数据库中创建了表之后,可以添加每个表字段的说明,使表更容易被理解和更新。在“项目管理器”中,从表的字段列表中选定一个字段之后,Visual FoxPro 就会显示该字段的注释文字。
若要在数据库表中向字段添加注释
– 或者 –
例如,可以输入“当前零售单价”作为字段的注释文字,来说明 orditems
表中的 unit_price
字段所存储的内容:
?DBSETPROP('orditems.price', 'field', 'comment', ;
'Current retail price per unit’)
有关使用 DBSETPROP( ) 设置数据库表字段属性的详细内容,请参阅第六章“创建数据库”。
在添加新记录时,要想让 Visual FoxPro 自动为某个字段填入内容,可以为该字段创建默认值。无论是在表单、“浏览”窗口或视图中输入数据,还是以编程方式输入数据,默认值都起作用,并一直存在于字段中,直到输入新值为止。
无论是通过“表设计器”还是通过编程,都可以创建默认值。默认值可以是除了通用型之外的任何数据类型。
若要给数据库表字段指定默认值
– 或者 –
例如,在应用程序中,对新顾客所订购的货物总量进行限制,直到您有时间去完成信用检查,并确定允许该顾客增加赊欠的数量之后,才对它进行更改。下面的例子创建了一个 maxordamt
字段,其默认值为 1000:
CREATE TABLE customer (cust_id C(6), company C(40), contact C(30), ;
maxordamt Y(4) DEFAULT 1000)
如果 customer
表已经包含了 maxordamt
字段,则可以使用以下命令为该字段指定默认值:
ALTER TABLE customer ALTER COLUMN maxordamt SET DEFAULT 1000
您可以通过使用默认值,来加快应用程序的用户输入数据过程。除非想输入不同的值,您可以跳过已包含了默认值的字段,从而节省输入数据的时间。例如,如果您的业务主要是处理国内顾客的信息,则可以使数据库中 customer
表的 country
字段自动填入本国国名。一旦要输入一名国外顾客的记录,可以用其他国名替换本国国名。
提示 如果应用程序中的某个商业规则要求一个字段必须有一个输入值,则提供默认值可以确保不会违反特定的字段级规则或记录级规则。
如果从数据库中移去或删除一个表,该表所有的默认值都将从数据库中删除。由被移去或删除的默认值所引用的存储过程,在移去默认值之后依然保留。
在没有指定默认值时,除非 SET NULL 设置成 ON,否则就会插入一个空值(空值内容由每种数据类型分别定义)。这样便保持了和任何已有 FoxPro 代码的向后兼容性。
如果允许字段使用 null 值,也可以用 .NULL. 作为字段的默认值。不管 SET NULL 是 ON 还是 OFF,如果使用 .NULL. 作为默认值,那么 Visual FoxPro 将为除 APPEND BLANK 以外的其他命令插入 .NULL.。
指定的默认值可以是数量值(比如一个具体的数字),也可以是等于一个数量值的表达式。您也可以指定任何一个有效的 Xbase 表达式,但该表达式的返回值要和该字段的数据类型相一致。
表结构被关闭时,Visual FoxPro 将对表达式求值。如果数据类型与相关的字段类型不匹配,Visual FoxPro 就会产生错误。如果表达式是用户自定义函数 (UDF) 或包含了 UDF,Visual FoxPro 将不对表达式求值。
当使用程序语言创建默认值时,如果数据类型不匹配,CREATE TABLE 或 ALTER TABLE 命令将会产生错误。如果表达式是 UDF 或包含 UDF,CREATE 在执行时将不对数据类型表达式求值,也不返回任何错误。
在执行 APPEND、APPEND BLANK 或 INSERT 命令时,默认值将被计算出来(如有必要)并放到适当的字段中。
在用 APPEND FROM 或 INSERT - SQL 命令指定值时,Visual FoxPro 将为所有没有明确指定值的字段指定默认值。APPEND FROM 和 INSERT_SQL 命令也可以接受默认值。但是,当发出一个这样的命令时,默认值并不改写字段中已有的值。如果追加或插入的字段中已经有值,则在追加或插入记录时,将保留其已有的值,而不使用默认值。
默认值对自动确定不允许为 null 值的字段特别有用。当添加新记录时,先使用默认值,然后根据定义好的顺序检查每个字段,查看是否遗漏信息。这样可确保指明为 NOT NULL 的字段在 NOT NULL 约束生效之前,先用默认值来填充。
指定输入掩码就是定义字段中的值必须遵守的标点、空格和其他格式要求。这样字段中的值就具有了统一的风格,从而可以减少数据输入错误,提高输入效率。例如,有一个字符型字段,用于存储电话号码,您可以为该字段指定一个掩码,定义分隔符或空格的位置。这样,当用户向该字段中填写电话号码时,就不用再考虑分隔符或空格的位置,加快了录入的速度。
若要提供输入掩码
– 或者 –
例如,以下代码指定了一个日期的输入掩码:
DBSetProp("orders.postalcode","field","InputMask", "99999-9999")
字段还具有其他一些属性,这些属性用于控制字段及其值如何在表单、“浏览”窗口和报表中显示;您还可指定显示格式,字段的默认标题,以及默认类及类库。
一个格式实质上是一个输出掩码,它决定了字段在表单、“浏览”窗口或报表中的显示风格。例如:
若要提供格式
– 或者 –
例如,以下代码指定了邮政编码的显示格式:
DBSetProp("orders.postalcode","field","Format","@R 99999-9999")
您可以为数据库表中的每个字段创建一个标题。Visual FoxPro 将显示字段的标题文字,并以此作为该字段在“浏览”窗口中的列标题,以及表单表格中的默认标题名称。
若要给数据库表的字段添加标题
– 或者 –
例如,可以输入“Supplier_Fax”作为 supplier
表的 fax
字段的标题。
?DBSETPROP('supplier.fax', 'field', 'caption', 'Supplier_Fax')
有关用 DBSETPROP( ) 函数设置数据库表字段属性的详细内容,请参阅第六章“创建数据库”。
为字段设置默认类可节省以后创建表单的时间。一旦指定,每次将字段加入表单时,表单控件使用指定的默认类。如,当将字符型字段加入表单时,文本框将自动出现。但如果您不想使用文本框而想使用组合框,那么您可以指定组合框为默认类。您还可使用自已创建的类库。
若要设置默认类
若经常改变字段的库和类,可在“选项”对话框中将字段数据类型映像至一个库和类中。有关映像字段数据类型至类的详细内容,请参阅《安装指南》中的第三章“配置 Visual FoxPro”。有关创建类的详细内容,请参阅本书第三章“面向对象程序设计”。
可以通过创建字段级和记录级规则,为数据的输入实施商业规则,以此来控制输入到数据库表字段和记录中的数据,这些规则称为有效性规则。字段级和记录级规则将把所输入的值与所定义的规则表达式进行比较,如果输入的值不满足规则要求,则拒绝该值。有效性规则只在数据库表中存在。
字段级和记录级规则能够控制输入到表中的信息类型,而不管数据是通过“浏览”窗口、表单,还是使用语言以编程方式来访问。它们可以使用户始终如一地对字段实施规则,所用的代码比在表单上用 VALID 子句,或者作为程序而编写的规则表达式代码要少。另外,建立在数据库中的规则可以对表的所有用户实施,而不理会应用程序的要求。
也可以创建候选索引或主索引,来防止字段中有相同的值。在数据库中的数据改变时,创建触发器可以加强参照完整性或进行其他操作。
可根据实施商业规则或参照完整性规则的级别,以及激活约束的动作来选择数据库的约束。下表列出了数据有效性规则的约束,它们按照 Visual FoxPro 引擎实施的顺序、应用级别以及引擎何时激活有效性检查的顺序进行排列:
实施机制 | 级 | 激活时机 |
NULL 有效性 | 字段/列 | 浏览时离开字段/列;在执行 INSERT 或 REPLACE 更改字段值时。 |
字段级规则 | 字段/列 | 浏览时离开字段/列;或在执行 INSERT 或 REPLACE 更改字段值时。 |
记录级规则 | 记录 | 发生记录更新时。 |
候选/主索引 | 记录 | 发生记录更新时。 |
VALID 子句 | 表单 | 移出记录时。 |
触发器 | 表 | 在 INSERT,UPDATE 或 DELETE 事件中,表中值改变时。 |
约束按它们在表中出现的顺序激活,任何未通过的有效性测试都会中止命令的执行。
候选索引和主索引在本章稍后的“控制重复值”一节中予以解释。
可以使用字段级有效性规则,来控制用户输入到字段中的信息类型,独立于其它记录的输入,检查该字段的数据。例如,可以使用字段级有效性规则,来确保用户不会在只允许正值的字段中输入负值,也可以使用字段级规则来比较输入字段中的值和其他表中的值。
不应该创建某一应用程序专有的字段级或记录级规则,应该用字段级和记录级有效性规则来实现数据完整性以及数据库数据固有的商业规则,而不管是谁将访问这些数据。例如,可以创建一条规则来对表的 postal_code 字段的输入值和包含有本国邮政编码的查找表进行比较,对于邮政编码查找表中没有的任何邮政编码缩写予以拒绝。
若要创建字段级规则
– 或者 –
– 或者 –
例如,可以使用以下代码,将一个字段级有效性规则添加到 orditems
表中,要求输入到 quantity
字段中的数字必须大于等于 1:
ALTER TABLE orditems
ALTER COLUMN quantity SET CHECK quantity >= 1
当用户试图输入一个小于 1 的值时,Visual FoxPro 就会显示一个错误信息对话框,并拒绝该值的输入。
可以通过给字段添加有效性文字,来定制当违反规则时要显示的提示信息。所输入的文字将代替默认的错误信息,并显示出来。
若要在字段级规则中添加自定义错误信息
– 或者 –
例如,可以使用以下代码,给 orditems
表添加字段级有效性规则,要求输入到 quantity
字段中的数值必须大于或等于 1,同时添加一条自定义错误信息:
ALTER TABLE orditems ;
ALTER COLUMN quantity SET CHECK quantity >= 1 ;
ERROR "Quantities must be greater than or equal to 1"
当用户试图输入小于 1 的值时,Visual FoxPro 将显示错误信息对话框及自定义的错误信息,并拒绝无效值。也可以把 ALTER TABLE 命令的 SET CHECK 子句和可选的 ERROR 子句一起使用,来创建自定义的错误信息。
了解何时检查字段级规则
字段级规则在字段值改变时发生作用。和触发器不同,即使数据在缓冲区中,字段级规则也可被激活。在“浏览”窗口、“表单”或其他用户界面窗口中处理数据时,如果焦点从字段上移开,Visual FoxPro 便检查字段级规则。如果字段值没改变,则不检查规则。这意味着可以自由地在字段之间移动,而系统不会检查任何数据。
字段级规则检查
数据输入方法 | 窗口或命令 | 检查字段级规则 |
用户界面 | “浏览”窗口 表单 其他用户界面 窗口 |
在从字段上移开时,如果字段值已经改变,则检查字段级规则(如果字段值不改变,则不检查规则)。 |
不指定字段的命令 | APPEND APPEND GENERAL APPEND MEMO BROWSE CHANGE DELETE EDIT GATHER |
在字段值改变时,检查字段级规则,按字段定义的顺序进行检查。 |
APPEND BLANK INSERT INSERT - SQL |
在追加或插入记录时,检查字段级规则。 | |
指定字段的命令 | UPDATE UPDATE - SQL REPLACE |
根据命令中指定字段的顺序,检查字段级规则。 |
使用记录级有效性规则,可以控制用户输入到记录中的信息类型。 记录级有效性规则通常比较同一记录中的两个或多个字段值,以确保它们遵守在数据库中建立的商业规则。例如,可以使用记录级有效性规则,来保证一个字段的值总是比同一记录中另一个字段值大。
若要创建记录级有效性规则和自定义错误信息
– 或者 –
例如,您为了确保雇员在被雇佣时,已经达到或超过了 18 岁,可以使用以下代码,给 employee
表添加记录级有效性规则和错误信息文字,要求输入到 hire_date
字段中的雇佣日期大于或等于雇员的生日加上 18 年:
ALTER TABLE employee SET CHECK ;
hire_date >= birth_date + (18 * 365.25) ;
ERROR "Employees must be 18 years or older by date of hire"
如果用户输入一个带有无效日期的雇员记录,Visual FoxPro 将会显示自定义的错误信息对话框,并且不更新该记录。
也可以使用 ALTER TABLE 命令的 SET CHECK 子句,来创建记录级有效性规则。必须确保为字段定义的任何规则在语义上不会与为表定义的规则发生冲突。Visual FoxPro 不比较字段级和记录级表达式是否一致。
了解何时检查记录级规则
和字段级规则一样,记录级规则在记录值改变时被激活。不管用什么方法处理数据(例如,在“浏览”窗口、“表单”、其他用户界面窗口中,或者使用改变数据的命令),当把记录指针移开记录时,Visual FoxPro 都要检查记录级规则。如果该记录中的值没有变化,则在移走记录指针时,不检查记录级规则。因此可以自由地在记录间移动指针,而系统却不会检查任何数据。
如果修改了记录但没有移动记录指针,准备关闭“浏览”窗口,这时仍然要检查记录级规则,并对所发生的任何错误提出警告,然后才关闭“浏览”窗口。
注意 在有效性规则中,请不要包含任何试图在当前工作区(即进行规则检查的工作区)中移动记录指针的命令和函数。如果在有效性规则中包括象 SEEK、LOCATE、SKIP、APPEND、APPEND BLANK、INSERT 或 AVERAGE、COUNT、BROWSE 和 REPLACE FOR 这样的命令和函数,会引起规则重复地被触发,并产生错误。
与触发器不同,即使数据在缓冲区时,记录级规则也会被激活。当在运行应用程序时激活了一条记录级规则,就需要有错误处理代码。通常,这意味着不允许应用程序离开表单(或者更一般的情况,改变活动环境),一直到用户改正错误或者取消更新为止。
如果从数据库中移去或删除一个表,则所有属于该表的字段级和记录级规则都会从数据库中删除。这是因为规则存储在 .dbc 文件中,而从数据库中移去表会破坏 .dbf 文件和它的 .dbc 文件之间的链接。但是,由被移去或删除的规则引用的存储过程不会被删除。它们不会自动地移去,因为保留在数据库中的其他表规则还在使用它们。
触发器是绑定在表上的表达式,当表中的任何记录被指定的操作命令修改时,触发器被激活。当数据修改时,触发器可执行数据库应用程序要求的任何副操作。例如,可以使用触发器做如下工作:
触发器作为特定表的属性来创建和存储。如果从数据库中移去一个表,则同时删除和该表相关联的触发器。触发器在进行了其他所有检查之后(例如有效性规则,主关键字的实施,以及 null 值的实施)被激活。与字段级规则和记录级规则不同,触发器不对缓冲数据起作用。
可以使用“表设计器”或 CREATE TRIGGER 命令来创建触发器。对于每个表,可为下面三个事件各创建一个触发器:插入、更新及删除。在任何情况下,一个表最多只能有三个触发器。触发器必须返回“真”(.T.) 或“假”(.F.)。
若要创建触发器
– 或者 –
例如,Tasmanian Trader 有可能在每次售出一项货物时,都想比较一下 Units_in_stock
和 Reorder_level
,并且在该项货物库存不够需要再次订购时发出通知。这时,可以在 products
表中创建“更新”触发器来完成这项任务。之所以选择“更新触发器”(而不是“删除触发器”或“插入触发器”),是因为您希望每次产品售出时都要激活触发器,而正好每次产品售出后都要更新 Units_in_stock
字段来反映库存的货物。
若要创建触发器,可以指定 updProductsTrigger( )
作为 products
表的“更新触发器”。可在 products
表中添加 reorder_amount
字段,来记录每次重新订购某产品的订货量,同时创建包含有 product_id
和 reorder_amount
字段的 reorder
表。然后在存储过程中添加下列代码:
PROCEDURE updProductsTrigger
IF (units_in_stock+units_on_order) <= reorder_level
INSERT INTO Reorder VALUES(Products.product_id, ;
Products.reorder_amount)
ENDIF
ENDPROC
使用 FOR INSERT 或 FOR DELETE 子句来代替 FOR UPDATE 子句,可以为插入和删除事件创建相似的触发器。创建一个已经存在的、属于某个专门事件和表的触发器时,如果 SET SAFETY 设置为 ON,Visual FoxPro 将提示您是否要改写已存在的触发器。
可以在界面中删除触发器或使用 DELETE TRIGGER 命令从数据库表中删除触发器。
若要删除触发器
– 或者 –
下面的示例从 customer
表中删除“更新触发器”:
DELETE TRIGGER ON customer FOR UPDATE
如果从数据库中移去或删除表,则所有属于该表的触发器都从数据库中删除。但是,由被移去或删除的触发器引用的存储过程没有删除。
可通过“表设计器”或者使用编程语言修改触发器。
若要修改触发器
– 或者 –
首先使用 SET SAFETY OFF 命令,然后重新创建触发器,以此来修改触发器。旧的触发器被自动删除,并由重新创建的触发器表达式代替。
Visual FoxPro 提供了“参照完整性生成器”建立触发器和存储过程,以此实现数据库的参照完整性 (RI)。有关使用“参照完整性生成器”的详细内容,请参阅第六章“创建数据库”。
建立表之后,还可以修改表的结构和属性。可能要添加、更改或删除字段的名称、宽度、数据类型,改变默认值或规则,或添加注释、标题。
可以打开“表设计器”修改表的结构,也可以使用 ALTER TABLE 命令以编程方式来更改表的结构。在修改表结构前,您必须独占地访问该表。
若要使用“表设计器”修改表的结构
– 或者 –
– 或者 –
例如,可以使用以下命令修改数据库中的 employee
表的结构:
OPEN DATABASE testdata
USE employee EXCLUSIVE
MODIFY STRUCTURE
前面的每种方法都要打开“表设计器”。
若要以编程方式修改表的结构
ALTER TABLE 命令提供了扩展子句,能够添加或去掉字段,创建或去掉主关键字、唯一关键字或外部关键字标识,并重新命名已有的字段。有些子句仅适用于与数据库相关联的表。本节将介绍几个具体示例。
可以通过“表设计器”或使用编程语言给表添加新的字段。
若要给表添加字段
– 或者 –
例如,可以使用以下命令把字段 fax
添加到 customer
表中,并允许该字段有 null 值:
ALTER TABLE customer ADD COLUMN fax c(20) NULL
可以通过“表设计器”或通过编程从表中删除已有的字段。
若要从表中删除字段
– 或者 –
例如,可以使用以下命令从 customer
表中删掉 fax
字段:
ALTER TABLE customer DROP COLUMN fax
从表中移去字段的同时,也移去了字段的默认值设置、规则定义和标题。如果索引关键字或触发器表达式引用了该字段,则该字段被移去后,表达式无效。无效的索引关键字或触发器表达式在运行之前不会产生错误。
可以用两种方法重新命名已有的表字段。
若要重新命名表字段
– 或者 –
例如,可以使用以下命令对 customer
表的 company
字段重新命名:
ALTER TABLE customer RENAME COLUMN company TO company_long_new_name
在前面的示例中,新字段名利用了在数据库表中创建长字段名的功能。
可以为字段级规则或表规则设置新的表达式和规则说明,也可以更改由 CREATE TABLE 或 ALTER TABLE 命令建立的规则和说明。
若要改变已有的规则
– 或者 –
用 DBGETPROP( ) 函数可查看当前的规则表达式和关联文本。这些值对表来说是只读的,并且只能使用 ALTER TABLE 命令更改。
建立表之后,可以设置或更改表字段的默认值。
若要改变已有的默认值
– 或者 –
用 DBGETPROP( ) 函数可查看当前字段的默认值。对表来说这些值是只读的,并且只能用 ALTER TABLE 命令来更改。
设计并创建了表的结构之后,就可以在表中添加新记录以存储数据,随后,可以更改或删除已有的记录,这些任务中的每一个都可以通过界面或命令来完成。本节主要讲述以编程方式处理记录。有关通过界面来处理记录的详细内容,请参阅《用户指南》中的第二章“创建表和索引”。
第一次创建 Visual FoxPro 表时,它将被打开且为空。只有在表中先创建记录,然后才能在表中存储数据。给新表添加记录的第一步是添加存储新数据的行。
若要在表中添加记录
INSERT - SQL 命令可以用来插入指定的值,或者插入来自数组或变量的值。例如,可以使用以下命令在 Tastrade 数据库的 customer
表中插入新记录:
INSERT INTO customer (cust_id, company, contact) ;
VALUES ("SMI007", "Smith's Delicatessen", "Sarah Smith")
INSERT-SQL 命令对远程数据也很有用,因为它使用符合 ANSI 标准的 SQL 句法。
也可以先使用 APPEND BLANK 在表中追加一个新的空记录,再用 REPLACE 命令用给定的值替换字段中的当前值(在这种用法中,当前值为空)。
REPLACE 命令要求有:
下例使用 APPEND BLANK 创建了一个记录之后,用 REPLACE 命令存储数据:
APPEND BLANK &&
记录现在可以使用了REPLACE lastname WITH "SMITH" &&
在字段中存储字符型值
可以使用 UPDATE - SQL 命令代替 REPLACE 命令,来更新表中的记录。
另一种在记录中存储数据的方法是复制在其他表或文件中的数据。 例如,可以从其他表或文件中获取要追加的记录。
若要从另一个文件里获取要追加的记录
– 或者 –
记录可以直接接受数据,比如,在前面的示例中 INSERT 命令指定了要插入到 customer
表中具体字段的文字值;类似的记录也可以从常量、变量、数组、对象以及其他数据源中接受数据。有关用其他方法输入数据的详细内容,请参阅《用户指南》中的第九章“导入和导出数据”。
若要在以浏览方式查看表时添加新记录,可以从“表”菜单中,选择“追加记录”。相反,若要防止用户在浏览方式下追加新记录,可以使用 BROWSE 命令的 NOAPPEND 子句。
可以采用交互方式、通过“浏览”窗口向表中输入数据,也可以用 REPLACE 或 UPDATE - SQL 命令以编程方式向表中输入数据。在多用户应用程序中使用 REPLACE 或 UPDATE - SQL 时,可以打开记录缓冲或表缓冲,这样在编辑数据时,在真正执行更改之前可以不用锁定记录。有关记录缓冲和表缓冲的详细内容,请参阅第十七章“共享访问程序设计”。
可通过界面或以编程方式显示和编辑表中已有的记录。
若要以可编辑方式显示记录
例如,可以使用以下代码在“浏览”窗口中以编辑方式显示 customer
表:
USE customer
EDIT
若要使用表单编辑记录,在表单中创建一个文本框,并把它的 DataSource 属性设成要编辑的表名。有关表单的详细内容,请参阅第九章“创建表单”。
也可以使用 CHANGE 和 EDIT 命令改变表中的指定字段。
通过创建通用字段并在其中导入或粘贴 OLE 对象(例如位图或图表),可以在 Visual FoxPro 表的字段中存储图形。APPEND GENERAL 命令把 OLE 对象放到通用字段中。下面的示例将一个 Microsoft Excel 图表文件从默认的 Visual FoxPro 目录存入名为 Chart 的通用字段:
APPEND GENERAL Chart FROM "CHART1.CLX" CLASS EXCELCHART
有关在 Visual FoxPro 表中处理 OLE 对象的详细内容,请参阅第十六章“添加 OLE”。
如果字段接受 null 值,则可以使用编程语言、通过 .NULL. 标记、或在界面使用组合键向字段中输入 null 值。
若要在字段中存储 null 值
– 或者 –
例如,可以使用以下代码将 automobile
字段中已有的值替换成 null 值。
REPLACE automobile WITH NULL
注释 用 SET NULLDISPLAY 命令可指定 null 值的显示文字。
删除记录时,先对记录作删除标记,然后再移去要删除的记录。在移去作了删除标记的记录之前,它们仍然存在于磁盘上,并可以撤消删除标记,恢复成原来的状态。本节说明了如何设置删除标记、撤消删除标记以及从表中移去记录。
可在界面中或使用 DELETE - SQL 命令对记录作删除标记。
若要对记录作删除标记
– 或者 –
– 或者 –
可以使用 DELETE - SQL 命令指定记录范围,还可以指定由逻辑表达式得到的条件,使要删除的记录必须满足这个条件。例如,可以使用以下代码对 discontinu
字段的值为“.T.”的所有产品记录作删除标记。
USE products
DELETE FROM products WHERE discontinu = .T.
BROWSE
在发出 PACK 命令之前,带有删除标记的记录并没有在物理上被删除。如果 SET DELETED 设置为 OFF,那么在“浏览”窗口中查看表时,可以看到每个要删除的记录都已标识了删除标记,但记录在表中仍可见。如果 SET DELETED 设置为 ON,则带有删除标记的记录在“浏览”窗口中不可见。
SET DELETED 命令的设置也同样影响了操作记录的命令能否作用于带有删除标记的记录。
可以使用 RECALL 命令撤消记录的删除标记。RECALL 命令只能在还没有发出 PACK 或 ZAP 命令之前恢复记录,PACK 和 ZAP 命令是在物理上把记录从表中删除。
若要撤消记录的删除标记
可以使用 RECALL 命令指定记录的范围,还可以指定由逻辑表达式得到的条件,记录必须满足这些条件才能撤消删除标记。例如,可以使用以下代码撤消 discontinu
字段的值为“.T.”的所有产品记录的删除标记。
USE products
RECALL FOR discontinu = .T.
BROWSE
当在“浏览”窗口中查看表时,可以看到记录的删除标记都已被清除。
对记录作了删除标记之后,可以通过界面或使用编程语言把它们从磁盘上永久地删除。
若要从磁盘上删除带有删除标记的记录
PACK 命令有两个子句:MEMO 和 DBF。当发出不带 MEMO 也不带 DBF 子句的 PACK 命令时,在表文件及与其相关联的备注文件中,所有带有删除标记的记录都将删除。例如,可以使用以下代码删除作了删除标记的记录:
USE customer EXCLUSIVE
PACK
若要仅删除表文件中的记录,而保留备注文件不动,请使用 PACK DBF 命令。
表中备注字段的信息存储在与表相关联的备注文件中,该文件有和表相同的名称和 .fpt 扩展名。如果想移去备注文件中不再使用的空间,但又不想从表中移去作了删除标记的记录,则应使用有 MEMO 子句的 PACK 命令。这时您必须独占地使用表。
如果想移去表中的所有记录,只留下表的结构,可使用 ZAP 命令。发出 ZAP 命令相当于执行 DELETE ALL 命令后再执行 PACK 命令,但 ZAP 更快。这时您必须以独占方式使用表。
注意 不能恢复从当前表中彻底删除的记录。
若要按特定的顺序定位、查看或操作表中记录,可以使用索引。Visual FoxPro 使用索引作为排序机制,为开发应用程序提供灵活性。根据应用程序的要求,可以灵活地对同一个表创建和使用不同的索引关键字,使您可按不同顺序处理记录。也能根据这些索引创建自定义表间关系,使您能准确地访问想要的记录。
Visual FoxPro 索引是由指针构成的文件,这些指针逻辑上按照索引关键字的值进行排序。索引文件和表的 .dbf 文件分别存储,并且不改变表中记录的物理顺序。实际上,创建索引是创建一个由指向 .dbf 文件记录的指针构成的文件。若要根据特定顺序处理表记录,可以选择一个相应的索引,使用索引还可以加速对表的查看和访问。
当第一次创建表时,Visual FoxPro 先创建表的 .dbf 文件,如果表中包含了备注型字段或通用型字段,Visual FoxPro 还要创建与表相关联的 .fpt 文件,此时并不产生索引文件。输入到新表的记录按照输入顺序存储,在浏览表时,记录按输入的顺序出现。
通常,要按特定顺序查看和访问新表中的记录。例如,按公司名字的字母顺序查看存储在顾客表中的记录。若要控制记录显示和访问的顺序,可以为表创建您的第一个排序方案或索引关键字,以此创建表的索引文件。然后可以根据这个索引关键字设置表中记录的顺序,并按新的顺序访问表的记录。
若要创建表的索引关键字
例如,可以使用以下代码,打开 customer
表并根据 city
字段创建索引关键字。关键字 TAG 和后面的词“city”为 city 字段的新索引关键字指定了一个名称,或叫标识。
USE customer
INDEX ON city TAG city
在前面的示例中,索引关键字标识使用和索引字段相同的名称。名称不一定要相同 -- 也可以为索引关键字命名不同的名称。
在第一次用 INDEX 命令创建索引时,Visual FoxPro 自动使用新索引来设置表中记录的顺序。例如,如果向前面创建的示例表中输入一些数据,然后浏览表,记录将按城市的顺序出现。
在前面的示例中,创建表的第一个索引关键字时,Visual FoxPro 自动创建一个新文件 Customer.cdx 存储新的索引关键字。索引关键字存储在带扩展名 .cdx 的文件中。这个 .cdx 文件,是结构复合压缩索引文件(.cdx 是指复合压缩索引,它分为结构复合压缩索引与非结构复合压缩索引),它是在 Visual FoxPro 数据库中最普通也最重要的一种索引文件。结构复合压缩索引文件:
一个 Visual FoxPro 表若有与之相关联的索引文件,则它通常是一个结构复合压缩索引文件。结构一词是指:Visual FoxPro 把该文件当作表的固有部分来处理,并在使用表时自动打开。无论使用“表设计器”,还是使用前面示例中出现的 INDEX 命令的最简单形式,Visual FoxPro 都用和当前表相同的基本名创建 .cdx 文件,并把新关键字或标识的索引信息存储在其中。可以将经常使用的索引关键字放到结构 .cdx 文件中。例如,在每日浏览、输入数据、SET RELATION 链接、对查看记录的 Rushmore™ 优化、以及经常使用的打印报表中进行记录排序时使用的索引关键字。
另外还提供两种类型的索引文件:非结构的 .cdx 文件和单关键字的 .idx 文件。因为结构 .cdx 或结构复合压缩索引是最重要的索引,本节中的大部分示例将讨论使用结构 .cdx 文件中的索引关键字对表记录进行排序。其他两种索引文件较少用到,将在本节的最后进行讨论。
可以将 TALK 设置为 ON,在索引过程中查看有多少个记录被编入索引。在索引过程中,显示的记录间隔可用 SET ODOMETER 指定。有关所有打开的索引文件的详细内容,请用 DISPLAY STATUS 命令。该命令列出了所有打开的索引文件、它们的类型(结构、.cdx 或 .idx)、它们的索引表达式以及主索引文件或主标识名。
能打开的索引文件 ( .idx 或 .cdx ) 数目只受内存及系统资源限制。
Visual FoxPro 支持四种索引:主索引、候选索引、唯一索引和普通索引。这些索引类型控制着在表字段和记录中是否允许或禁止重复值。
主索引绝对不允许在指定的字段或表达式中有重复值。主索引主要用于在永久关系中的主表或被引用表里建立参照完整性。一个表只能创建一个主索引。如果在任何已经包含了重复数据的字段中指定主索引,Visual FoxPro 将返回一个错误信息。
候选索引也不允许在指定的字段或表达式中有重复值。候选这个名词是指索引的状态。因为候选索引禁止重复值,因此它们在表中有资格被选作主索引,即主索引的“候选项”。
对一个表可以创建多个候选索引。在永久关系中,可以使用候选索引作为永久关系中被引用(或引用)的索引来建立参照完整性。
如果在任何包括重复数据的字段中指定候选索引,Visual FoxPro 将返回一个错误信息。
可以使用 CREATE TABLE 或 ALTER TABLE 命令创建主索引或候选索引。在定义“一对多”或“一对一”永久关系中的“一”方时,既可以使用候选索引,也可以使用主索引。
若要创建主索引或候选索引
– 或者 –
例如,使用以下两个命令中的任何一个都能将 cust_id
字段做为 customer
表的主关键字:
ALTER TABLE customer ADD PRIMARY KEY cust_id TAG cust_id
ALTER TABLE customer ALTER COLUMN cust_id c(5) PRIMARY KEY
表的主索引和候选索引存储在给定表的结构 .cdx 文件中,同时以 Primary 属性或 Candidate 属性存储在数据库中。这些类型的索引不能保存在其他 .cdx 文件中,也不能使用 .idx 文件保存这些索引。这主要是因为:不论与它们相关联的表何时打开,包含这些索引的索引文件总要随之打开。
在数据库中,主关键字是表的一部分,所以如果您把一个表从数据库中移出,使之成为自由表,主关键字将丢失。
在与数据库相关联的索引表达式中,如果使用用户自定义函数,Visual FoxPro 将使用与处理包含 UDFs 的规则和触发器表达式的同样方法来处理这些表达式。
在 Visual FoxPro 中,唯一索引允许存在重复值。但是,唯一索引只存储索引文件中重复值的第一次出现。在这种意义上,“唯一”指的是索引文件中入口值是唯一的,因为它对每一个特定的关键字只存储一次,而忽略了其重复值的第二次或以后的出现。用唯一索引进行索引的表可以包含重复值,提供唯一索引类型主要是为了保证向后兼容性。
不是唯一索引、主索引或候选索引的索引就是普通索引。可以使用普通索引排序和查找记录,在这些记录中并不要求数据的唯一性。在“一对多”永久关系的“多”方,可以使用普通索引。
若要创建普通索引
例如,可以使用以下命令为 customer
的表创建 city
普通关键字:
USE customer
INDEX ON city TAG city
在处理表中记录的过程中,将会发现需要使用几种不同的顺序来访问表。例如,您可能想根据 contact 字段对表 customer
进行排序,以便迅速找到所需的名字;或者根据 postal_code 字段创建邮件标签,这些标签为有效邮寄进行预选排序。
通过在同一表中创建多个索引关键字,可以创建和存储表的许多不同排序方案。这样,便可以在不同的时候,根据不同的目的分别对表记录排序。
若要创建表的附加索引关键字
例如,可以使用以下代码创建 employee
表的两个新的索引关键字,一个根据 last_name
字段,另一个根据 country
字段:
USE employee
INDEX ON last_name TAG last_name
INDEX ON country TAG country
在创建索引标识时,若没有指定索引文件名,该标识自动加入到表的 .cdx 结构索引文件中。下面的图例显示了一个有三个索引标识的 .cdx 索引文件。
.cdx 索引包括多个标识,代表着多个记录排序方案
图中的两个标识 emp_id
和 last_name
,是基于单个字段的索引,cntry_last
索引则用两个字段的简单索引表达式对记录排序。有关根据多个字段生成一个索引的详细内容,请参阅本章稍后的“使用表达式进行索引”部分。
根据 customer
表的 company
、city
字段和 country
字段创建索引关键字之后,便可以按不同的顺序访问和显示该表,只要简单地选择相应的索引关键字即可。可以用 SET ORDER 命令选择具体的索引关键字作为表的排序关键字。
例如,使用以下代码打开“浏览”窗口,并按国家/地区的顺序显示 customer
表中的记录:
SET ORDER TO country
BROWSE
SET ORDER 可以指定主控索引文件或标识。表可以有许多同时打开的索引文件。当然,要决定显示或访问表中记录的顺序,还要设置一个单项索引 (.idx) 文件(主控索引文件)作为主控索引,或设置复合索引 (.cdx) 文件中的一个标识(主控标识)作为主控索引。有些命令使用主控索引标识来搜索记录,如 SEEK。查询时不需要使用 SET ORDER。
在运行时刻,可以使用 SET ORDER 改变表单中记录的顺序。例如,您可能想在用户单击列标头时,根据该表中此列的顺序重新排序一个表格中的记录。
若要在表格中按列对记录进行排序
例如,如果基于 Testdata 数据库的 Customer 表创建表单,其中有一个表格,表格中有四列:company
、contact
、postal code
和 phone
。表格最初显示时按字母顺序排序,因为表中的记录是按字母顺序输入的。
表格中,按照公司名称的字母顺序排序的 Customer 表
然后,便可以在每个列标头的 Click 事件中插入以下代码,使用户可以按 contact
或 postal_code
的顺序查看表格。
在表格中通过单击列标头进行记录排序的示例事件代码
代码 | 注释 |
|
在 Company 标头的 Click 事件代码中,根据 Company 索引关键字对表格重新排序,并刷新表单,显示按公司名称排序的记录。 |
|
在 Contact 标头的 Click 事件代码中,根据 Contact 索引关键字重新排序,并刷新表单,显示按合同名称排序的记录。 |
|
在 Postal_Code 标头的 Click 事件代码中,根据 Postal_Code 索引关键字对表格重新排序,并刷新表单,显示按邮政编码排序的记录。 |
因为本程序不要求根据电话号码排序,所以 Phone 标头 Click 事件代码为空。 |
本例中,在表单第一次显示时,表格按照公司名称的字母顺序显示。当用户单击 Contact 列标头时,Visual FoxPro 根据合同名称的字母顺序显示表格中的记录。
表格中,按合同名称的字母顺序排序 Customer 表
如果用户单击 Postal_code
列标头,表格重新排序,并按邮政编码顺序显示。
表格中,按邮政编码排序的 Customer 表
由于在我们的示例程序中,不需要根据电话号码对合同排序,因此在 Phone 列标头的 Click 事件中,没有插入 SET ORDER 代码。用户单击 Phone 列标头时,表格显示不变。
除了最普通的索引( 结构 .cdx索引),Visual FoxPro 还支持其他两种索引文件:非结构的 .cdx 索引和独立的 .idx 索引。 非结构的 .cdx 索引用于很少使用的多关键字标识;独立的 .idx 索引用于暂时的或不经常使用的单关键字索引,独立的 .idx 索引主要是为了满足向后兼容性。
下表是这三种索引类型的总结:包括它们如何命名,可以包含的关键字数目,每种索引的字符限制。
Visual FoxPro 索引类型
索引类型 | 描述 | 关键字数目 | 限制 |
结构 .cdx | 使用和表文件名相同的基本名,随表的打开自动打开。 | 多关键字表达式,称为标识。 | 有效表达式限制在 240 个字符之内。 |
非结构 .cdx | 必须明确地打开,使用和表名不同的基本名。 | 多关键字表达式,称为标识。 | 有效表达式限制在 240 个字符之内。 |
独立 .idx | 必须明确地打开,.idx 文件的基本名由用户定义 | 单关键字表达式。 | 有效表达式限制在 100 个字符之内。 |
由于特殊的目的,有时想创建多个索引标识,但又不想在运行过程中维护这些索引,因为这样会增加应用程序的负担。此时,非结构 .cdx 索引很有用。例如,您的应用程序中有一组专门的报表,分析一些字段的数据,但这些字段并没有建立正常索引。应用程序就可以创建一个包含所需索引标识的非结构 .cdx 索引,然后运行这些专门的报表,最后再删除非结构 .cdx 文件。
若要创建非结构 .cdx 索引标识
使用 INDEX 命令的 OF 子句,可以使 Visual FoxPro 将标识定向到另一文件中,而不保存到表的 .cdx 结构索引文件中。例如,使用以下命令,可以创建 employee
表的 title
和 hire_date
标识,并把它们存储在非结构 .cdx 文件 QRTLYRPT.cdx
中:
USE employee
INDEX ON title TO TAG title OF QRTLYRPT
INDEX ON hire_date TO TAG hiredate OF QRTLYRPT
独立索引文件基于单关键字表达式,并保存在 .idx 文件中。.cdx 文件可以存储多关键字表达式,.idx 索引只存储单关键字表达式。
通常可以使用独立索引作为临时索引,在需要它们时再创建或重新编排这些索引。例如,有一个只用于每季度或每年度总结报表的索引。如果把这个不经常使用的索引包括到结构 .cdx 文件中,便要求在每次使用表时都要维护它,因此最好创建一个独立 .idx 索引。对一个特定的表,可创建任意多个 .idx 文件。
若要创建独立 .idx 索引
使用带有 COMPACT 子句的 INDEX 命令,可以在一个小的、能快速访问的索引文件中创建一个新的独立索引。如果想创建一个与以前的 FoxBASE+® 及 FoxPro® 1.0 版本的索引格式兼容的非压缩独立 .idx 文件,则可以省略 COMPACT 子句。
可以使用以下代码,在 orders
表中按 order_date
创建一个独立 .idx 文件,根据新索引设置排序,然后打开“浏览”窗口,根据 order_date
的顺序显示排序:
USE ORDERS
INDEX ON order_date TO orddate COMPACT
SET ORDER TO orddate
BROWSE
可以使用 COPY TAG 命令,从已存在的 .cdx 文件的索引标识中复制一个独立索引文件。例如,您可能会发现目前保存在结构 .cdx 中的一个索引只用于季度或年度报表,可以使用以下代码根据 employee
表的 birth_date
标识创建一个独立索引:
COPY TAG birth_date to birthdt COMPACT
从 .cdx 文件的标识创建独立索引之后,通常会从 .cdx 文件中删除不再需要的标识。下一节说明如何删除索引。
可通过删除 .cdx 文件中的标识来删除不再使用的索引,或者通过删除 .idx 文件本身来删除独立索引。删除无用的索引标识可以提高性能,因为 Visual FoxPro 不必再去更新无用标识,来反映表中数据的变化。
可以通过“表设计器”或使用语言从 .cdx 结构文件中删除标识。
若要删除在结构 .cdx 文件中的索引标识
– 或者 –
– 或者 –
例如,可以使用以下代码删除 employee
表中包含的 title
标识:
USE employee
DELETE TAG title
可以使用 ALTER TABLE 命令删除 employee 表的主关键字标识:
USE employee
ALTER TABLE DROP PRIMARY KEY
非结构 .cdx 索引和它的标识在“表设计器”中不可见。只能使用语言从非结构 .cdx 文件中删除标识。
若要删除非结构 .cdx 文件中的索引
可以使用 DELETE TAG 命令的 OF 子句,指示 Visual FoxPro 从其他不同于结构 .cdx文件的 .cdx 文件中删除标识。例如,可以使用以下命令删除非结构 .cdx 文件 QTRLYRPT.cdx
中的标识 title
:
DELETE TAG title OF qtrlyrpt
可以使用 DELETE TAG 命令的 ALL 子句,删除结构或非结构 .cdx 文件中的所有标识。
由于独立索引文件只包含单索引关键字表达式,所以可通过从磁盘上删除 .idx 文件来删除表达式。
若要删除独立 .idx 文件
例如,以下代码删除独立 .idx 索引文件 Orddate.idx:
DELETE FILE orddate.idx
也可以使用 Windows 资源管理器等工具删除独立 .idx 文件。
可创建基于表达式的索引,并以此提高应用程序的性能。这些表达式可繁可简,这取决于要实现的功能。
简单索引表达式基于单字段、或者基于两个以上字段组成的多字段关键字。例如,可以根据下面的表达式创建 TasTrade 数据库中 Customer 表的索引:
country + region + cust_id
当浏览根据这个索引标识排序的 Customer 表时,可以看到顾客已根据国家/地区进行排序,然后是地区,最后根据顾客的 ID 号进行排序。
若要通过多字段避免重复值,可根据组合的多字段表达式创建主索引或候选索引。
例如,有一个表,其中有两个字段存储了电话区号和电话号码:
电话区号 | 电话号码 |
206 | 444-nnnn |
206 | 555-nnnn |
313 | 444-nnnn |
电话区号字段和电话号码字段都分别包括和其他行重复的值。当然实际生活中电话号码不可能重复,因为只有两个字段组合在一起才构成实际的电话号码。如果主索引或候选索引在索引表达式中指定了两列,那么在示例中的行就是不可重复的。若输入一个电话区号和电话号码与已存在行完全相同的值,Visual FoxPro 会把这个输入作为重复值而拒绝。
可以使用包含 null 值的字段创建索引。等于 .NULL. 的索引表达式插入到 .cdx 文件或 .idx 文件的非 null 值之前,所有的 null 值都放在索引的开始部分。
下面的示例演示了索引 null 值的效果。这是未使用索引之前表的状态:
有两个记录的 SocSec 字段为 null 值
两个记录中的 null 值表示 Anne Dunn 和 Alan Carter 的社会福利号 (SocSec) 要么不知道,要么无效。然后可以使用下面语句,根据社会福利号创建索引:
INDEX ON SocSec + LastName + FirstName TAG MyIndex
当根据这个索引查看表时,将看到如下图所示的排序结果。
按 SocSec 索引之后,包含 null 的 SocSec 的记录首先出现
当索引表达式包括 null 值时,SocSec
值为 .NULL. 的记录首先排序(根据 LastName
),然后排序 SocSec
值不是 null 的记录。请注意 Alan Carter 有两个记录。因为第 5 个记录包含 null 值,所以第 5 个记录在第 2 个记录之前索引。
也可以根据更复杂的表达式创建索引。Visual FoxPro 索引关键字表达式可以包括 Visual FoxPro 函数、常量或用户自定义函数。
创建的表达式对于独立 (.idx) 索引标识来说不能超过 100 个字符,对于 .cdx 索引标识来说不能超过 240 个字符。在一个标识中,通过把表达式的单个组件转换成字符类型,可以一起使用不同的数据类型。
若要利用 Rushmore™ 技术进行优化,索引表达式必须符合 Rushmore 的要求。
在索引标识中可以使用 Visual FoxPro 函数。例如,可以使用 STR( ) 函数把一个数值型值转换成字符串。如果想在 customer
表中创建一个将 cust_id
字段和 maxordamt
字段组合起来的索引标识,可以使用以下代码,将 maxordamt
字段从 8 个字节的货币型字段转换成有两个小数位的 8 字符字段:
INDEX ON cust_id + STR(maxordamt, 8, 2) TAG custmaxord
若要减小包含整数的字段索引的大小,可用 BINTOC( ) 函数将整数转换为其对应二进制数所代表的字符。也可用 CTOBIN( ) 函数作相反的转换。
如果想创建一个根据日期对表进行排序的索引,可以使用 DTOS( ) 函数把日期字段转换成字符串。若要根据 hire_date
和 emp_id
访问 employee
表,可以使用以下代码创建这个索引关键字表达式:
INDEX ON DTOS(hire_date) + emp_id TAG id_hired
在索引表达式中,可以引用存储过程或用户自定义函数,以提高索引性能。例如,可以使用存储过程或 UDF(用户自定义函数),从包括街道号和街道名的单个字段中抽取出街道名。如果街道号总是数值型的,存储过程或 UDF 可以返回字段的字符部分,并用所需的空格来填充所得字符串,以创建一个定长的索引关键字。然后就可以使用这个索引关键字按街道名的顺序访问表中记录。
如果表与数据库相关联,则在索引中最好使用存储过程,而不要使用 UDF。因为 UDF 存储在数据库以外的文件中,很有可能在操作中移动或删除 UDF 文件,这将使引用 UDF 的索引标识无效。相反,存储过程代码存储在 .dbc 文件中,Visual FoxPro 总能找到它。
在索引标识中,使用存储过程的另外一个优点是:引用存储过程可以保证索引所基于的指定代码是正确的。如果在索引表达式中使用 UDF,那么在索引时,当前作用域内和被引用的 UDF 同名的任何一个 UDF 都可能被使用。
注释 在索引表达式中,引用存储过程或 UDF 时要小心,因为它会增加创建索引所需要的时间。
可以使用在其他工作区中打开的表创建索引标识。对引用多个表的标识,使用独立索引 (.idx) 是很明智的。这是因为如果在 .cdx 结构文件中包括了引用其他表的标识,在索引标识中引用的表没有打开时,Visual FoxPro 则不允许打开建立索引的表。
可通过创建降序索引,按降序读取已有的索引,按降序查看记录。
若要创建降序索引
若要创建复合结构索引(结构 .cdx)文件,这两种方法都可以使用。若要创建其他类型的索引文件,则可以使用第二种方法。例如,可以使用以下代码创建新的降序索引,根据 unit_price
从高到低对 product
表进行排序,并根据新的排序浏览表:
USE products
INDEX ON unit_price TAG unit_price DESCENDING
BROWSE
若要按降序读取已有的索引
按降序读取已有的索引,可以调整已有的索引而不用创建新索引。例如,可以使用以下代码创建索引,它根据 unit_price
字段对 product
表进行排序:
USE products
INDEX ON unit_price TAG unit_price
默认时,排序是升序的,但可以使用以下代码按降序浏览表:
USE products
SET ORDER TO unit_price DESCENDING
BROWSE
前面的示例主要说明了按降序访问信息。SET ORDER 和 INDEX 两个命令都提供了 ASCENDING 子句,可以在应用程序中组合这两个命令以获得更大的灵活性。例如,可以使用 ASCENDING 或 DESCENDING 子句来按常用的顺序创建索引,再使用 SET ORDER 命令中的相反子句,按相反的排序查看或访问其中的信息。
可以使用筛选索引把所访问的记录限制在指定的数据上。当创建了筛选索引之后,只有符合筛选表达式的记录才可显示和访问。
要使用筛选索引筛选数据
如果在 INDEX 命令中包含了 FOR 可选子句,索引文件就具有筛选的功能。在索引文件中,只为那些符合筛选表达式的记录创建索引关键字。例如,您正在整理准备发给公司销售代表的邮件,如果想根据国家/地区名称排序邮件,则可以创建索引来筛选 employee
表,筛选出那些销售代表的记录,并按他们的国家/地区和姓名排序。可以使用以下代码创建筛选索引,并在“浏览”窗口中显示筛选出来的数据:
USE employee
INDEX ON country+last_name FOR title = "Sales Representative" ;
TAG reps_cntry
BROWSE
在“浏览”窗口中查看表时,只显示销售代表,其他雇员记录根本不在“浏览”窗口中出现。
筛选索引为仅满足筛选表达式的记录生成索引
可用 SET FILTER 命令暂时筛选数据,而不用生成专门的筛选索引。若要指定一个暂时的条件,使表中只有满足该条件的记录才能访问时,这个命令特别有用。如果要关闭当前表的筛选条件,可以执行不带表达式的 SET FILTER TO 命令。例如,可以使用以下命令筛选 customer 表,只显示德国(Germany)的顾客:
USE customer
SET FILTER TO country = "Germany"
BROWSE
SET FILTER 命令接受任何一个有效的 Visual FoxPro 逻辑表达式作为筛选条件。如果使用 SET FILTER 命令,在表中只有满足筛选条件的记录才可访问,所有访问表的命令都遵守 SET FILTER 条件。可为每个打开的表设置独立的筛选条件。
保持索引的当前状态并使用优化的索引表达式,可以提高进行索引的表的性能。
若打开一个表而不打开其相应的索引文件,并更改表中与索引相关的关键字段内容,则索引文件就会过时。当系统被破坏或者从非 Visual FoxPro 程序中访问和更新表索引文件时,都可能导致索引文件无效。 如果索引文件过时,可以使用 REINDEX 命令重建索引,更新它们。
若要重建活动索引文件
例如,可以使用以下命令更新 customer 表的索引文件:
USE customer
REINDEX
REINDEX 更新选定工作区中打开的所有索引文件。Visual FoxPro 识别每种索引文件类型(非结构 .cdx 文件、结构 .cdx 文件 和 .idx 独立文件),并相应地重建索引。它更新 .cdx 文件中的所有标识,并更新与表一起自动打开的 .cdx 结构文件。
也可以使用 REINDEX 命令更新过时的索引文件。
重建索引很费时间。特别是对很大的表重建索引时,时间很长,因此只有在必须时才重建索引。可以在程序的初始部分和结束部分重建索引来提高性能,而最好不要在应用程序的主体部分进行索引维护。
可以使用索引加快查询和其他操作。有关创建 Rushmore 优化索引表达式的详细内容,请参阅第十五章“优化应用程序”。
若要使用多个表,就要使用多个工作区。一个工作区是一个编号区域,它标识一个已打开的表。可以在 32767 个工作区中打开和操作 Visual FoxPro 表。在应用程序中工作区通常通过使用该工作区的表的别名来标识。表别名是一个名称,它可以引用在工作区中打开的表。
除了在“数据工作期”窗口中的可见工作区之外,Visual FoxPro 还通过数据工作期自动为表单或表单集的每个实例提供一个独立的环境。一个数据工作期是指表单、表单集或报表使用的当前动态工作环境。每个数据工作期包含了它自己的一组工作区,这些工作区包括在工作区中打开的表、表索引以及表之间的关系。有关数据工作期的详细内容,请参阅第十七章“共享访问程序设计”。
打开“数据工作期”窗口,可查看在一个 Visual FoxPro 工作期中已打开表的列表。
若要打开“数据工作期”窗口
– 或者 –
当在“命令”窗口中键入 SET 时,Visual FoxPro 打开“数据工作期”窗口,并显示在当前数据工作期中打开表的工作区别名。
打开 Employees 表时的“数据工作期”窗口
可以使用“数据工作期”窗口或使用 USE 命令在工作区中打开表。
若要在工作区中打开表
如果要在最低可用工作区中打开表,可以在 USE 命令 IN 子句后面加工作区 0。例如,如果工作区 1 到 10 中都有打开的表,可以使用以下命令,在工作区 11 中 打开 customer 表:
USE customer IN 0
在“文件”菜单中选择“打开”,也可以在工作区中打开表。
可通过“数据工作期”窗口或使用语言关闭工作区中的表。
若要在工作区中关闭表
当执行不带表名的 USE 命令,并且在当前所选工作区中有打开的表文件时,则关闭该表。例如,可以使用以下代码打开 customer 表,显示“浏览”窗口,然后关闭此表:
USE customer
BROWSE
USE
当在同一工作区中打开其他表,或者发出有 IN 子句的 USE 命令并指定当前工作区时,可以自动关闭已打开的表。下面的代码通过发出 USE IN 命令和 customer
表别名,打开 customer
表,然后显示它,最后关闭:
USE customer
BROWSE
USE IN customer
在一个工作区中,不能同时打开多个表。
可以象下面显示的那样,在下一个可用工作区中打开表之前,指出该工作区的编号:
SELECT 0
表别名是 Visual FoxPro 用来指定在一个工作区中打开的表的名称。打开一个表时,Visual FoxPro 自动使用文件名作为默认表别名。例如,如果用下面的命令在 0 号工作区打开文件 CUSTOMER.DBF,则自动为表指定默认别名 customer
:
SELECT 0
USE customer
然后,可以使用别名 customer
在命令或函数中标识该表。也可创建自己的别名。
在打开表时,可以为它指定用户自定义的表别名。
若要以用户自定义的别名打开表
例如,可以使用以下命令,在 0 号工作区中打开文件 CUSTOMER.DBF,并为它指定一个别名 people
:
SELECT 0
USE customer ALIAS people
然后必须使用别名 people 引用打开的表。别名最多可以包括 254 个字母、数字或下划线,但首字符必须是字母或下划线。如果所提供的别名包含不支持的字符,则 Visual FoxPro 会自动创建一个别名。
在以下情况中,Visual FoxPro 自动指定表的别名:
在前 10 个工作区中指定的默认别名是工作区字母 A 到 J,在工作区 11 到 32767 中指定的别名是 W11 到 W32767。您可以象使用任何默认别名或用户自定义别名那样,使用这些 Visual FoxPro 指定的别名来引用在一个工作区中打开的表。
可以使用 SELECT 命令从一个工作区移到另一个工作区。例如,如果在一个工作区中打开 CUSTOMER.DBF 并指定默认别名 CUSTOMER,可以使用下面的 SELECT 命令移到这个工作区中:
SELECT customer
在别名后加上点号分隔符“.”或“->”操作符,然后再接字段名,可以引用其他工作区中的字段。例如,可以使用以下代码,在一个工作区中访问其他工作区中打开的 Customer 表的 contact
字段
customer.contact
如果要引用的表是用别名打开的,则也可以使用别名。例如,如果 Customer 表是使用别名 people
打开的,那么,可以使用以下代码引用表中的 lastname
字段:
people.lastname
可以在一个表所在的工作区之外,使用表名或表别名来明确标识该表。
在建立表间的临时关系后,就会使得一个表(子表)的记录指针自动随另一个表(父表)的记录指针移动。这样,便允许当在关系中“一”方(或父表)选择一个记录时,会自动去访问表关系中“多”方(或子表)的相关记录。
例如,可以关联 customer
表和 orders
表,此后当把 customer
表的记录指针移到一个特定顾客时,orders
表的记录指针也移到有相同的顾客标号的记录上去。
可以使用 SET RELATION 命令、使用表工作区和表别名建立两个打开的表之间的关系。如果正在使用表单处理表,则可以把这些关系作为表单的数据环境的一部分保存起来。
可以通过“数据工作期”窗口或使用语言来创建表间的临时关系。
若要临时关联表
– 或者 –
SET RELATION 命令可以建立两表之间的关系,其中一个是在当前选定工作区中打开的表,而另一个则是在其他工作区中打开的表。通常这两个表具有相同字段,而且用来建立关系的表达式常常就是子表主控索引的索引表达式。
例如,顾客可以有许多相关联的订单记录。如果在两个表共同拥有的字段之间创建关系,就能很容易地看到任何一个顾客的所有记录。下面程序中,在创建 customer
表中的 cust_id
字段和 orders
表中的 cust_id
索引标识之间的关系时,使用了两个表都有的字段 cust_id
。
使用 SET RELATION 建立两个表间的关系
代码 | 注释 |
|
在 1 号工作区中打开 customer 表(父表)。 |
|
在 2 号工作区中打开 orders 表(子表)。 |
|
选定子表工作区。 |
|
使用索引标识 cust_id 指定子表的顺序。 |
|
选定父表工作区。 |
|
创建父表和子表的主控索引之间的关系。 |
|
打开两个“浏览”窗口,请注意:移动父表的记录指针会改变在子表中显示的数据集合。 |
“数据工作期”窗口显示两个打开的表:orders
和 customer
,并通过 SET RELATION 命令建立关系。
“数据工作期”窗口显示已打开表的别名和临时关系
在上面的例子中,假设您已在子表 orders 中创建了一个索引,根据订货的顾客对表中记录进行分组。当创建父表和子表之间的关系后,Visual FoxPro 在子表中只选择那些索引关键字和父记录的索引关键字相匹配的记录。
前面的示例建立两个表之间的单一关系,也可以用 SET RELATION 命令建立单个父表和不同子表之间的多个关系。
若要创建一个使用多个表的表单,可以使用数据环境创建表关系,并把它们和表单存储在一起。运行表单时,在数据环境中建立的关系自动打开。有关创建数据环境的内容,请参阅第九章“创建表单”。
可以在单个表中创建记录间的关系,即自引用关系。若所需要的所有信息都存储在单个表中,这种关系很有用。例如,如果遍历 Employees 表中的经理,随着记录指针从一个经理到另一个经理的移动,每个经理的雇员自动更改。
若要临时关联单个表中的记录
– 或者 –
若要创建自引用关系,可以两次打开同一个表,在一个工作区中打开一个表,并使用 USE AGAIN 命令在另外工作区中再次打开此表,然后使用索引来关联记录。例如,可以使用以下代码,根据 reports_to
字段对 employee
表进行排序,然后创建索引标识 mgr
_id,并以此建立并浏览一个自引用关系:
SELECT 0
USE employee ALIAS managers
SELECT 0
USE employee AGAIN ALIAS employees
INDEX ON reports_to TAG mgr_id
SET ORDER TO mgr_id
SELECT managers
SET RELATION TO emp_id INTO employees
BROWSE
SELECT employees
BROWSE
当在 managers
“浏览”窗口中移动记录指针时,会自动刷新 employees
“浏览”窗口,并在其中显示隶属于选定经理的雇员。
索引用于在数据库中建立表间的永久关系。永久关系是存储在数据库文件中的关系,并在“查询设计器”和“视图设计器”中,自动作为默认连接条件使用的数据库表间关系。永久关系在“数据库设计器”中显示为表索引间的连接线,当在该数据环境中打开这些表时,永久关系也作为默认关系显示。
与 SET RELATION 命令设置的临时关系不同,永久关系在每次使用表时不需要重新创建。但是,由于永久关系并不控制表中记录指针间的关系,因此在开发 Visual FoxPro 应用程序时,不仅需用永久关系,也需使用临时的 SET RELATION 关系。有关设置永久关系的详细内容,请参阅第六章“创建数据库”。