在应用程序中,若要创建自定义并且可更新的数据集合,可以使用视图。视图兼有表和查询的特点:与查询相类似的地方是,可以用来从一个或多个相关联的表中提取有用信息;与表相类似的地方是,可以用来更新其中的信息,并将更新结果永久保存在磁盘上。可以用视图使数据暂时从数据库中分离成为自由数据,以便在主系统之外收集和修改数据。
本章将介绍如何以编程方式创建和更新视图,同时说明如何通过设置属性来优化视图的性能。有关数据库的详细内容,请参阅第六章“创建数据库”。若需要有关表和索引的详细内容,请参阅第七章“处理表”。有关“视图设计器”的详细内容,请参阅《用户指南》中的第五章“使用视图更新数据”。
本章内容要点:
由于视图和查询有很多类似处,创建视图与创建查询的步骤相似。选择要包含在视图中的表和字段,指定用来联接表的连接条件,指定过滤器选择指定的记录。与查询不同的是,视图可选择如何将在视图中所做的数据修改传给原始文件,或建立视图的基表。
创建视图时,Visual FoxPro 在当前数据库中保存一个视图定义,该定义包括视图中的表名、字段名以及它们的属性设置。在使用视图时,Visual FoxPro 根据视图定义构造一条 SQL 语句,定义视图的数据。有关视图属性的详细内容,请参阅本章稍后的“设置视图属性和连接属性”然后查看 DBGETPROP( ) 或 CURSORGETPROP( )。
可以创建两种类型的视图:本地视图和远程视图。远程视图使用远程 SQL 语法从远程 ODBC 数据源表中选择信息,本地视图使用 Visual FoxPro SQL 语法从视图或表中选择信息。您可以将一个或多个远程视图添加到本地视图中,以便能在同一个视图中同时访问 Visual FoxPro 数据和远程 ODBC 数据源中的数据。有关在单个视图中访问远程数据和本地数据的详细内容,请参阅本章稍后的“在视图中集成本地数据和远程数据”部分。
可以使用视图设计器或 CREATE SQL VIEW 命令创建本地视图。
若要创建本地视图
- 或者 -
- 或者 -
例如,可以使用以下代码创建包含 products
表中所有字段的视图:
CREATE SQL VIEW product_view AS SELECT * ;
FROM testdata!products
新视图的名称将显示在“项目管理器”中。如果打开“数据库设计器”,您会看到视图的显示方式与表在分层结构中的显示方式相同,所不同的是视图名代替了表名。
在上例中,表名的前面带有(或者说被限定)表所在的数据库名和一个“!”符号。在创建视图时,如果表名前限定有数据库名,Visual FoxPro 将在已打开的数据库中(包括当前的和所有非当前的数据库)以及默认搜索路径中寻找该表。
如果在视图定义中没有给表限定数据库名,那么在使用该视图前,数据库必须打开。
提示 在“项目管理器”中创建或使用视图时,“项目管理器”会自动打开数据库。如果要使用项目外的视图,则必须先打开数据库或事先确认数据库在作用范围内。
可以使用宏替换将 SQL SELECT 语句存入一个变量,再用 CREATE SQL VIEW 命令的 AS 子句来调用。例如,下面的代码将一条 SQL SELECT 语句存入emp_cust_sql
变量,然后用它创建一个新视图。
emp_cust_sql = "SELECT employee.emp_id, ;
customer.cust_id, customer.emp_id, ;
customer.contact, customer.company ;
FROM employee, customer ;
WHERE employee.emp_id = customer.emp_id"
CREATE SQL VIEW emp_cust_view AS &emp_cust_sql
使用“项目管理器”或命令语言,可在“视图设计器”中修改已有的视图。若要以编程方式修改视图的 SQL 命令串,则必须创建新视图,保存视图定义并覆盖旧视图。有关修改视图属性的内容,请参阅本章稍后“设置视图属性和连接属性”。
提示 用编程方式创建视图时有一个窍门:在“视图设计器”中,可打开一个已有的视图,复制只读的 SQL 字符串,并粘贴到代码中。
若要在“视图设计器”中修改视图
- 或者 -
在“视图设计器”中,使用“查询”菜单或“视图设计器”工具栏将新表添加到视图中。下面的代码在“视图设计器”中显示 product_view
视图。
OPEN DATABASE testdata
MODIFY VIEW product_view
可以使用项目管理器或 RENAME VIEW 命令重新命名视图。
若要更改视图的名称
- 或者 -
例如,下面代码将视图 product_view
重命名为 products_all_view
:
RENAME VIEW product_view TO products_all_view
在重命名视图之前,包含此视图的数据库必须打开。
可以使用“项目管理器”或 DELETE VIEW 命令从数据库中删除视图定义。删除视图前,包含此视图的数据库必须已打开并已设置为当前数据库。
若要删除视图
- 或者 -
例如,下面的代码从数据库中删除 product_view
视图和 customwe_view
视图:
DELETE VIEW product_view
DROP VIEW customer_view
注释 这两个命令是等价的,DROP VIEW 是删除 SQL 视图的 ANSI SQL 标准语法。
要想访问存贮在不同表中的相关信息,可以创建一个视图并加入两个或更多的表,或在已有视图中加入表。添加表,可以使用“视图设计器”或 CREATE SQL VIEW 命令。加入表后,使用表之间定义的连接条件,进一步对视图结果进行控制。
要创建多表视图
- 或者 -
只使用 CREAT SQL VIEW 命令将表加入视图,而不定义相应的联接条件,会得到表之间的“叉乘”,既表中记录的任意可能组合。所以需要在语句的 FROM 或 WHERE 子句指定联接条件,这样只有符合联接条件的不同表中的记录才被组合在一起。如果表间存在永久关系,将自动用作联接条件。
典型情况下,可使用由表间的主关键字和外部关键字建立的关系,定义联接条件。在联接条件中比较它们公有的字段值(通常使用相等作为比较条件)。例如,要查阅有关订单的信息,要求包括下订单的客户信息。可创建一个由 Custom 表和 Orders 表生成的视图,在这个例子中 Customer 和 Orders 表有同一字段 Customer ID 。
若要在视图中定义联接条件
- 或者 -
“视图设计器”中指定的内部联接,及它在 SELECT-SQL 语句中的表示
以下代码创建一个如上例描述的新视图,用 FROM 子句指定视图的联接条件。
OPEN DATABASE testdata
CREATE SQL VIEW cust_orders_view AS ;
SELECT * FROM testdata!customer ;
INNER JOIN testdata!orders ;
ON customer.cust_id = orders.cust_id
联接条件有以下几个要素:联接类型,建立联接的字段和用于联接字段的比较操作符。在上面的例子中,联接的类型为内部联接,customer
表的记录只有与 orders
表的一个或多个记录相匹配,才会被包含在结果中。
若要改变视图的结果以满足特定需求,可指定:
在主关键字和外部关键字以外的字段间建立联接在特定的实例中也很有用,但并不常用。
通过比较操作符,可以控制比较和返回的记录,这种方式类似于过滤器。例如,如果联接条件中使用的是日期型字段,可选用适当的比较操作符使得返回结果中只包括某段时间内的记录。
有关联接顺序的详细内容,请参阅本章稍后的“定义多表间的联接条件”。
选择不同的联接类型,可以扩展查询结果,使结果中既包括与联接条件匹配的记录也包含与联接条件不匹配的记录。如果视图中不止两个表,还可通过改变 FROM 子句中的联接顺序改变结果。
可用“视图设计器”和编程语言修改视图中的联接类型。
若要修改联接类型
- 或者 -
- 或者 -
如果要在结果中包含不匹配的行,可用外部联接。例如,需要一个所有客户的清单,而不管客户是否有订单。另外,对有订单的客户,需要在视图中包括订单数。当使用外部联接,不匹配行的空字段将返回 NULL 值。
通过以下代码,可用编程语言创建这个视图:
OPEN DATABASE testdata
CREATE SQL VIEW cust_orders_view AS ;
SELECT * FROM testdata!customer ;
LEFT OUTER JOIN testdata!orders ;
ON customer.cust_id = orders.cust_id
若要控制那些包含在视图中的不匹配记录,可选择以下的联接类型。
若要 | 请使用 |
只返回完全满足联接条件的记录。 | 内部联接 |
返回 JOIN 关键字左侧表中的所有记录以及右侧表中匹配的记录。 | 左外部联接 |
返回 JOIN 关键字右侧表中的所有记录以及左侧表中匹配的记录。 | 右外部联接 |
返回两个表中的匹配和不匹配的所有记录。 | 全外部联接 |
如果创建包含两个以上表的视图或查询,可通过改变联接条件的顺序,改变结果。例如,要查找有关订单的信息,其中包括完成订单的雇员,以及下订单的客户。可创建一个基于 customer
表、orders
表和 employee
表的视图,在它们公有的字段间建立内部联接:customer
表和 orders
表都有 customer ID 字段,orders
表和 employee
表都有 employee ID 字段。
此视图基于如下的 SQL 语句:
OPEN DATABASE testdata
CREATE SQL VIEW cust_orders_emp_view AS ;
SELECT * FROM testdata!customer ;
INNER JOIN testdata!orders ;
ON customer.cust_id = orders.cust_id ;
INNER JOIN testdata!employee ;
ON orders.emp_id = employee.emp_id
可以在 WHERE 子句中指定联接条件,但不能象在 FROM 子句的联接中那样指定联接类型。对于远程视图,联接条件通常出现在 WHERE 子句中。
以下代码创建的视图与前例相同,使用 WHERE 子句指定此视图的联接条件:
OPEN DATABASE testdata
CREATE SQL VIEW cust_orders_emp_view AS ;
SELECT * FROM testdata!customer, ;
testdata!orders, testdata!employee ;
WHERE customer.cust_id = orders.cust_id ;
AND orders.emp_id = employee.emp_id
若要使用远程服务器上的数据,可以创建远程视图。为了创建远程视图,必须首先连接一个数据源。
一个远程数据源通常是一个远程服务器,已为它在本地安装了 ODBC 驱动程序并设置了 ODBC 数据源名称。为得到有效的数据源,必须在本地安装 ODBC。从 Visual FoxPro 内部可定义数据源和联接。
有关设立 ODBC 数据源的详细内容,请参阅《安装指南》中的第一章“安装 Visual FoxPro”。
在 Visual FoxPro 中,您可以在数据库中创建并保存一个命名连接的定义,以便在创建远程视图时按其名称进行引用,而且还可以通过设置命名连接的属性来优化 Visual FoxPro 与远程数据源的通讯。当您激活远程视图时,视图连接将成为通向远程数据源的管道。
若要创建命名连接
- 或者 -
- 或者 -
例如,为了从 ODBC 数据源 sqlremote
获取所需的有关信息,可以用以下代码在 testdata
数据库中创建连接:
OPEN DATABASE testdata
CREATE CONNECTION remote_01 DATASOURCE sqlremote userid password
这时,“项目管理器”的“连接”中将出现 remote_01
。
在数据库中,创建命名连接并不会用到任何网络或远程资源,因为 Visual FoxPro 只有要使用视图时才激活连接。在激活连接之前,命名连接只作为一条连接的定义,在数据库的 .dbc 文件中占据一行。当您使用远程视图时,Visual FoxPro 根据视图中引用的命名连接,创建一个活动连接与远程数据源相连,然后将此活动连接作为管道向远程数据源发送数据请求。
您可以创建一个仅指定数据源名称而无连接名称的视图。当您使用此视图时,Visual FoxPro 将使用有关该数据源的 ODBC 信息来创建并激活一个通向此数据源的连接。当您关闭此视图时,连接也相应关闭。
在使用带有 CONNECTION 子句的 CREATE SQL VIEW 命令时,既可以使用连接的名称也可以使用数据源的名称。Visual FoxPro 首先在当前数据库中搜索具有此名称的连接。如果数据库中不存在此命名连接,Visual FoxPro 再根据此名称查找已建立的 ODBC 数据源。如果当前数据库中的命名连接与您系统上的 ODBC 数据源同名,则 Visual FoxPro 将首先查找并使用命名连接。
当使用一个视图而又未充分指定其连接注册信息时,Visual FoxPro 将显示一个与数据源相关的对话框,提示您输入漏掉的信息。
在进行连接时,也可以控制 Visual FoxPro 是否提示输入未指定的信息。
若要控制 ODBC 注册提示的显示
- 或者 -
可以使用已有的命名连接来创建远程视图。使用项目管理器或 DISPLAY CONNECTIONS 命令可以在数据库中看到一个可用连接的列表。
若要了解已有连接的情况
- 或者 -
例如,下面的代码显示 testdata 数据库中的连接:
OPEN DATABASE testdata
DISPLAY CONNECTIONS
在建立了有效的数据源或命名连接之后,就可以使用项目管理器或以编程方式来创建远程视图。远程视图与本地视图类似,只是在定义它时需要加入连接名称或数据源名称。远程视图的 SQL 语句使用相应服务器上的语法。
若要创建远程视图
- 或者 -
如果使用了带有 CONNECTION 子句的 CREATE SQL VIEW 命令,就可以不加入 REMOTE 关键字。Visual FoxPro 根据 CONNECTION 关键字是否存在来判断视图是否为远程。例如,如果将 Testdata 数据库中的 products
表放到远程服务器上,则可用下面的代码创建此表的远程视图:
OPEN DATABASE testdata
CREATE SQL VIEW product_remote_view ;
CONNECTION remote_01 ;
AS SELECT * FROM products
在创建远程视图时,可以使用数据源而不使用命名连接。在使用带有 REMOTE 子句的 CREATE SQL VIEW 命令时,也可以忽略连接名或数据源名,这时 Visual FoxPro 将显示“选择连接或数据源”对话框,您可以在这个对话框中选择一个有效的连接或数据源。
创建了视图后,打开“数据库设计器”,可看到视图在分层结构中与表具有相同的显示方式,只不过是视图的名称和图标代替了表的名称和图标。
如果在“视图设计器”中联接两个和多个表,设计器将联接条件加入 WHERE 子句并使用内部联接(或相等联接)。如果要用外部联接,“视图设计器”仅提供 ODBC 语法支持的左外部联接。如果需要右外部联接或全外部联接,亦或只是想用左外部联接的远程数据库的本地语法,可用编程方式创建视图。
视图建立之后,不但可以用它来显示和更新数据,而且还可以通过调整它的属性来提高性能。处理视图类似于处理表,可以:
既可以通过“项目管理器”,也可以借助 Visual FoxPro 语言来使用视图。
若要使用一个视图
下面的代码在浏览窗口中显示 product_view
:
OPEN DATABASE testdata
USE product_view
BROWSE
一个视图在使用时,将作为临时表在自己的工作区中打开。如果此视图基于本地表,则在 Visual FoxPro 的另一个工作区中同时打开基表。视图的基表是指由 SELECT - SQL 语句访问的表,此语句在创建视图时包含在 CREATE SQL VIEW 命令中。在前面的示例中,使用 product_view
视图的同时,products
表也自动打开。
数据工作期窗口显示视图及其基本表
如果此视图基于远程表,则基表将不在工作区中打开,而只在数据工作期窗口中显示远程视图的名称。
在访问远程数据源时,很可能会访问大量数据。这时可以在视图中限定被选数据的范围,以便在某一时刻只出现所需的记录,从而降低网络通信量,改善视图性能。例如,如果想要浏览某地区的客户及其订单时,可以仅下载该地区而非全部客户的记录来提高性能。
一种限定视图作用范围的方法是在视图的 SQL 语句中加入 WHERE 子句。若要查询瑞典客户的记录,可以创建如下 SQL WHERE 子句:
SELECT * FROM customer ;
WHERE customer.country = 'Sweden'
上面的代码仅下载瑞典客户的记录,因而有效限定了视图的作用范围。但是如果要了解其他国家/地区的情况,就不得不为每个国家/地区单独创建一个视图,因为每个国家/地区的 customer.country
值在视图的 SELECT 语句中是固定的。
参数化视图也可以用来限定视图的作用范围,而使用参数化视图可以避免每取一部分记录就需要单独创建一个视图的情况。参数化视图在视图的 SQL SELECT 语句中加一条 WHERE 子句,从而仅下载那些符合 WHERE 子句条件的记录,其中的子句是根据所提供的参数值建立的,参数值可以在运行时传递,也可通过编程方式传递。
对于前面的示例,可以创建一个通用视图,在需要得到某一国家/地区的记录时,只需键入相应国家/地区的名称即可。
若要创建参数化视图
- 或者 -
这个参数可以是一个 Visual FoxPro 表达式,计算出来的值将作为视图 SQL 语句的组成部分。若计算无效,Visual FoxPro 将提示输入该参数值。例如,如果将 Testdata 数据库中的 customer
表放在远程服务器上,则可用下面的代码创建一个远程参数化视图。这个视图将对客户记录进行筛选,如果客户的国家/地区与提供给 ?cCountry
的参数值相匹配,则该客户记录在视图中出现;否则不出现。
OPEN DATABASE testdata
CREATE SQL VIEW customer_remote_view ;
CONNECTION remote_01 ;
AS SELECT * FROM customer ;
WHERE customer.country = ?cCountry
在使用这个视图时,也可以通过编程方式来提供 ?cCountry
参数值。例如,可以键入如下代码:
cCountry = 'Sweden'
USE Testdata!customer_remote_view IN 0
BROWSE
这时,在 Customer_remote_view
视图的浏览窗口中,Visual FoxPro 显示瑞典客户的记录。
视图只显示 country 字段值与所提供参数相匹配的记录
提示 如果参数是表达式,请用圆括号将该表达式括起来,这将使整个表达式被作为参数的一部分进行计算。
如果要求输入的参数不是一个变量或表达式,那么您也许会希望给用户一个提示。这时,可以将字符串用引号括起来并以此作为视图参数。如果在创建视图参数时使用“?”符号,后面加上一个用单引号括起的字符串,Visual FoxPro 就不把该字符串看作一个表达式,而是在运行时刻将其作为提示,提示用户输入参数值。例如,下面的代码创建了一个远程参数化视图,提示用户为 ?'my customer id'
参数提供一个值。
OPEN DATABASE testdata
CREATE SQL VIEW customer_remote_view ;
CONNECTION remote_01 ;
AS SELECT * FROM customer ;
WHERE customer.cust_id = ?'my customer id'
USE customer_remote_view
在使用上例的视图时,显示如下“视图参数”对话框。
“视图参数”对话框提示输入由引号内字符串说明的值
在输入有效的客户 ID 值之后,Visual FoxPro 将检索与此 ID 值相匹配的记录。若在上例中输入‘ALFKI’,然后浏览 Customer_remote_view
视图,您将在浏览窗口中看到相应的客户记录。
浏览窗口显示 cust_id 为 ALFKI 的记录
使用加引号的字符串作为视图参数,可以确保 Visual FoxPro 在要求得到参数值时,总是对用户作出提示。
与可在多个工作区中打开同一个表一样,可以在不同的工作区中打开一个视图的多个实例。与表不同的是:在默认情况下,每次使用视图时,都要去取一个新的数据集合。
若要在多个工作区中打开一个视图
- 或者 -
- 或者 -
在使用 USE 命令以编程方式访问视图时,不必重新查询数据源就可以打开视图的另一个实例。这对于在多个工作区中打开一个远程视图的情况特别有用,因为不需要等待从远程数据源下载数据。
若要不下载数据再次使用视图
下面的代码使用 NOREQUERY 子句在两个浏览窗口中显示从 product_remote_view
的第一个实例中得到的临时表,而不重新查询远程数据源:
OPEN DATABASE testdata
CREATE SQL VIEW product_remote_view ;
CONNECTION remote_01 ;
AS SELECT * FROM products
USE product_remote_view
BROWSE
SELECT 0
USE product_remote_view NOREQUERY
BROWSE
在使用 NOREQUERY 子句时,您可以指定一个工作期编号。如果不指定工作期编号,Visual FoxPro 将对全部工作期进行搜索以查找结果集合。若找到了打开的结果集合,就将在这个结果集合上再次打开一个临时表;若没找到打开的结果集合,则为该视图取一个新的结果集合。和处理表一样,若未找到视图,则打开一个新的视图临时表。
如果要求 Visual FoxPro 只在当前工作期内搜索已打开的视图结果集合,可以使用 AGAIN 子句。下面的代码在两个浏览窗口中显示 product_remote_view
视图:
OPEN DATABASE testdata
USE product_remote_view
BROWSE
USE product_remote_view AGAIN in 0
BROWSE
在使用 AGAIN 子句时,Visual FoxPro 在当前工作期中查找一个已存在的视图临时表,并打开一个指向该视图临时表的附加别名。打开视图的另一个实例时,使用 AGAIN 子句与使用属于 USE 的 NOREQUERY 子句(带当前工作期编号)等效。
可以使用带 NODATA 子句的 USE 命令,仅打开视图并显示视图结构。当想要看到远程视图的结构而又不想等待下载数据时,此选项非常有用。
若要打开一个不带数据的视图
下面的代码在浏览窗口中显示不带数据的 customer_remote_view
视图:
OPEN DATABASE testdata
USE customer_remote_view NODATA in 0
BROWSE
使用带 NODATA 子句的视图总会打开一个新的视图临时表。NODATA 子句是获取视图结构最快的方法,因为它在远程数据源上创建最小的临时表。使用 NODATA 子句时,Visual FoxPro 为视图创建一个永远返回“假”值的 WHERE 子句。因为数据源上没有记录能够匹配 WHERE 子句的条件,所以没有记录被选择进入远程数据源的临时表。这样,该视图可被快速检索,因为不必等待远程数据源去建立一个可能很大的临时表。
提示 使用 NODATA 子句比设置视图或临时表的 MaxRecords 属性为 0 更为有效。当使用 MaxRecords 属性时,必须等待远程数据源建立起一个视图临时表,而此视图临时表包含全部符合正常 WHERE 子句条件的数据行。建立视图临时表之后,再根据 MaxRecords 的属性设置情况,下载这个远程视图临时表中的数据行。
可以使用 INDEX ON 命令,为视图创建本地索引,创建过程与表一样。与表的索引不同的是,在视图上创建的本地索引非永久保存,它们随着视图的关闭而消失。
提示 在决定是否要在视图上创建本地索引时,请考虑视图结果集合的大小。对一个大的结果集合建立索引,要花费很长的时间并降低视图的性能。
有关创建索引的详细内容,请参阅第七章“处理表”或者参阅 INDEX 。
可以使用 SET RELATION 命令,在视图索引之间或视图索引与表索引之间创建临时关系。
在使用 SET RELATION 命令对一个视图与一个表进行关联时,若要获得较好的性能,请在关系中设视图为父表,设表为子表。这是因为在临时关系中,子对象必须按其索引排序。表的结构索引是在不断被维护的,因此可以快速访问;而对于视图,Visual FoxPro 要在视图每次激活时为其重建索引,因此很浪费时间。此外,如果使用数据环境,视图将不能被当作子对象,因为子对象的索引必须是定义的一部分,而视图并不支持此功能。
在创建一个视图时,这个视图将从环境临时表或从当前工作期的临时表 0 中继承属性设置,如 UpdateType 和 UseMemoSize。可以使用 CURSORSETPROP( ) 函数并以 0 作为临时表编号来更改默认的属性设置。在视图建立并存入数据库之后,可以使用 DBSETPROP( ) 函数修改视图属性。在数据库中,修改的视图属性将长期保存在数据库中。
在使用视图时,数据库中保存的视图属性设置将被活动视图临时表继承。可以使用 CURSORSETPROP( ) 函数,为视图临时表修改活动临时表的属性。但是,使用 CURSORSETPROP( ) 函数进行的修改是临时的,在关闭视图后,活动视图的临时设置将消失;在结束 Visual FoxPro 工作期时,0 号临时表的临时设置也将消失。
连接也以类似方式继承属性。当您在数据库中创建并保存一个命名连接时,0 号连接的默认属性将被继承,可以使用 SQLSETPROP( ) 函数修改 0 号连接的默认属性。在数据库中创建并保存连接之后,可以使用 DBSETPROP( ) 函数修改连接属性。在使用连接时,数据库中为连接保存的属性设置将被活动连接继承。您可以使用 SQLSETPROP( ) 函数并使用该活动连接的句柄来修改连接的这些属性。
视图与连接都可以使用一个有指定名称的 ODBC 数据源。若在视图中使用 ODBC 数据源,连接将继承工作期的默认属性。
下图展示了视图和连接的属性继承关系。灰线代表属性继承关系,黑线代表 Visual FoxPro 命令。
视图属性和连接属性及其继承关系
当创建视图时,视图中所有字段的 DataType 属性设为默认值。对于固定长度的数据类型,用字母(D,G,I,L,M,P,T,Y)表示,对于可变长度的数据类型,用字母及其后圆括号中的表示精度和范围的参数 (B(d), C(n), N(n,d)) 来表示。对本地视图此属性为只读属性。默认数据类型的列表,请参阅第二十一章“实现客户/服务器应用程序”中的“下载和上载远程视图数据”。
可用 DBSETPROP( ) 函数修改远程视图的字段 DataType 属性的设置。如下图所示 :
远程字段的 ODBC 数据类型 | 在 Visual FoxPro 临时表中的可用数据类型 |
SQL_CHAR SQL_VARCHAR SQL_LONGVARCHAR |
字符型或备注型1(默认);也可以是通用型或图片 |
SQL_BINARY SQL_VARBINARY SQL_LONGVARBINARY |
备注型(默认);也可以是字符型,通用型或图片 |
SQL_DECIMAL SQL_NUMERIC |
数值型或货币2(默认);也可以是字符型,整型或双精度 |
SQL_BIT | 逻辑型(默认);也可以是字符型 |
SQL_TINYINT SQL_SMALLINT SQL_INTEGER |
整型(默认); 也可以是字符型,数值型,双精度或货币 |
SQL_BIGINT | 字符型(默认);也可以是整型,数值型,双精度或货币 |
SQL_REAL SQL_FLOAT SQL_DOUBLE |
双精度(默认);小数的位数是 Visual FoxPro 中 SET DECIMALS 设置的值;也可以是字符型,整型,数值型,或货币 |
SQL_DATE | 日期型(默认);也可以是字符或日期时间 |
SQL_TIME | 日期时间3(默认);也可以是字符 |
SQL_TIMESTAMP | 日期时间4(默认);也可以是字符或日期 |
1 如果 ODBC 字段宽度小于临时表 UseMemoSize 属性值,则在 Visual FoxPro 临时表中为字符型字段,否则将成为备注型字段。
2 如果服务器上的数据源是钱的数据类型,则在 Visual FoxPro 中成为货币数据类型。
3 日期默认为1/1/1900。
4 如果 SQL_TIMESTAMP 字段的值包含表示秒的小数位,则当值转换为 Visual FoxPro 的日期时间数据类型时,小数部分被截断。
可用 DataType 属性选择不同于默认值的数据类型。例如,要将服务器上的时间戳型字段下载到 Visual FoxPro 中。默认情况下,映射到 Visual FoxPro 的数据类型为日期时间型,数据中,服务器时间戳中表示秒的小数部分被截断。用 DataType 属性将远程时间戳字段映射到 Visual FoxPro 的字符型字段,以保留表示秒的小数部分。
在使用视图时,自动打开的本地基表并不在关闭视图时自动关闭,必须另发命令关闭它们,这与 SELECT - SQL 命令保持一致。
在视图中更新数据与在表中更新数据类似。不过,使用视图还可以对其基表进行更新。视图在默认情况下使用开放式行缓冲。也可以将其改为表缓冲。有关缓冲的详细内容,请参阅第十七章“共享访问程序设计”。
可以通过交互方式更新视图中的数据,也可以使用语言进行更新。更新视图数据的第一步就是设置该视图为可更新。在多数情况下,属性的默认设置将自动使视图可更新,但只有将 SendUpdates 属性设置为 On 来通知 Visual FoxPro 进行更新时,更新信息才被发送到数据源。
视图使用五个属性控制更新。这些属性及其默认设置在下表列出:
视图更新属性及其默认设置
视图属性 | 默认设置 |
Tables | 具有可更新字段和至少一个主关键字段的全部表。 |
KeyField | 数据库关键字段和表的远程主关键字。 |
UpdateName | 所有字段,形式为 Table_name.column_name 。 |
Updatable | 除主关键字段的所有字段。 |
SendUpdates | 默认设置只在工作期内有效,初始值为“假”(.F.),若将其改为“真”(.T.),则成为在工作期内所创建的全部视图的默认值。 |
CompareMemo | 默认为真(.T.)指备注字段包含在 WHERE 子句中,用来检测更新冲突。 |
在更新数据时,虽然以上五个属性都需要,但 SendUpdates 属性是其中的“主开关”,它控制了是否发送更新信息。在应用程序的开发阶段,您可以先关闭 SendUpdates 属性,设置其他属性使希望更新的字段可以被更新。在测试应用程序时,可以打开 SendUpdates 属性允许发送更新数据流。
在一些复杂情况下,默认的更新设置可能不支持用语言创建的视图进行更新。若要使其能够更新数据,请检查每个更新属性的默认设置,并根据需要调整它们。也可以根据需要,指定附加的属性,如 UpdateType,WhereType 等。有关视图属性的完整内容,请参阅 DBGETPROP( )。
若要在“视图设计器”中使视图可更新
通过视图设计器创建的视图,默认设置通常允许视图被更新,您所需要做的只是选中“发送 SQL 更新”复选框来打开更新开关。如果愿意,您还可以修改表、字段、SQL WHERE 子句和更新选项。
若要通过设置视图更新属性使视图可更新
尽管默认的设置能够提供更新视图所需的全部信息,但您最好还是了解一下在下面列出的、以编程方式指定五个视图更新属性的步骤:
注释 默认的视图属性可提供更新视图的全部所需信息。
例如,如果您有一个基于 customer
表的名为 cust_view
视图,可以使用以下函数设置表名:
DBSETPROP('cust_view','View','Tables','customer')
提示 如果一个表在 UpdateName 属性中以限定符形式出现,而又不包含在 Tables 属性的默认列表之中,那么这个表可能没有指定主关键字段。通过向 KeyField 属性列表中加入可作为关键字段的字段,使该表可更新,然后将此表加入 Tables 属性的列表之中。
对于上例,可以用以下代码使 cust_id
成为关键字段:
DBSETPROP('cust_view.cust_id','Field','KeyField',.T.)
注意 请确认您所指定的关键字段可作为基表和视图中的唯一关键字。
DBSETPROP('cust_view.cust_id','Field','UpdateName',;
'customer.cust_id')
提示 为避免在视图中使用同名字段,请在创建视图的 SQL 语句中对字段名加限定字符串,然后使用视图的 UpdateName 属性,将每个限定的字段与相应的基表和字段名建立映射关系。
DBSETPROP('cust_view.cust_id','Field','Updatable',;
.T.)
DBSETPROP('cust_view','View','SendUpdates',.T.)
在使用视图前,如果通过 DBSETPROP( ) 函数设置视图的属性,那么这些设置将保存在数据库中,并在激活视图时自动启用。视图激活之后,可以使用 CURSORSETPROP( ) 函数改变活动视图的属性设置。在关闭视图时,此方式设置的活动视图的属性不被保存。
可以在一个视图中更新多个表。若视图组合了两个或多个表,那么可以设置相应属性,使得只有视图查询中一对多关系的“多”方可被更新。
视图的更新是对表进行的。对于视图访问的每一个表,其关键字段集合无论对视图结果集合还是对基表都是唯一关键字。
若要使一个多表视图可更新
- 或者 -
在多数情况下,Visual FoxPro 的默认值允许多表视图可更新,即使是对于以编程方式创建的多表视图也是如此。下面的代码示例创建了一个两表视图,并明确设置属性对其进行更新。您可以将这个示例作为在视图上设置更新属性的一个范例程序来加以研究。
在视图中更新多个表
代码 | 注释 |
|
创建一个视图,能访问两个表中的字段 |
|
设置表使其可更新 |
|
设置可更新字段名 |
|
为 Employee 表设置单字段唯一关键字 |
|
为 Customer 表设置双字段唯一关键字 |
|
设置可更新字段。通常,关键字段不可更新 |
|
激活更新功能 |
|
在视图中修改数据 |
|
通过更新 Employee 和 Customer 基表,提交修改 |
因为视图存于数据库中,所以您可以对视图创建:
视图的数据字典在功能上与数据库表中的相应部分非常相似。但是,您必须以语言方式而不能用表设计器为视图创建标题、注释、默认值和规则。
与表的字段默认值相类似。视图的字段默认值存于数据库中,并且在每次使用视图时都可用。Visual FoxPro 并不对本地创建的默认值与远程数据源创建的默认值相比较,但您创建的默认值必须能让数据源接受。
若要给视图字段指定默认值
- 或者 -
例如,您可能希望自己的应用程序限制客户的订货数量,直到完成对客户的信用检查,并且确定了客户的信用数额,才继续接受订货。下面的示例就创建了这样一个默认值为 10000 的 maxordamt
字段:
OPEN DATABASE testdata
USE VIEW customer_view
?DBSETPROP ('Customer_view.maxordamt', 'Field', 'DefaultValue', 1000)
也可以使用默认值为用户自动生成一些数据行。例如,在“订单输入”表单中加入表格控件。此表单处理一个基于订单项目表的远程视图,其中 order_id 字段是关键字段,用来将表格中的每一行映射到其远程订单项目表中的相应位置。因为对于相同订单,表格中每一行的 order_id 都相同,因此可以使用默认值自动生成 order_id
字段,省去不必要的录入工作。
提示 如果应用程序的某一商业规则要求某一字段接受录入值,那么使用默认值有助于确保所使用的值不违反特定的字段级规则或记录级规则。
对远程数据源规则创建相应的本地版本,可以带来以下好处:
Visual FoxPro并不将本地创建的规则与远程规则进行比较。您必须保证创建的规则可被数据源接受。如果远程规则有所更改,本地规则也必须随之更改。
若要在视图字段或记录上创建规则
- 或者 -
例如,下面的代码对 orditems_view
视图创建了字段级规则,防止输入的数量小于 1:
OPEN DATABASE testdata
USE VIEW orditems_view
DBSETPROP('Orditems_view.quantity','Field', ;
'RuleExpression', 'quantity >= 1')
DBSETPROP('Orditems_view.quantity','Field', ;
'RuleText', ;
'"Quantities must be greater than or equal to 1"')
您也可以使用 DBSETPROP( ) 函数创建数据行级规则。
您可以在其他视图的基础上再创建视图。这样做的理由是:有时需要从多个其他视图中获取一部分信息,或者需要将本地和远程数据集成到单个视图中。一个基于视图的视图,或基于集成了本地表、本地视图或远程视图的视图,被称为多级视图。集成了其他视图的视图为顶层视图。在顶层视图与本地基表或远程基表之间,可以有多个层次的视图。在使用多级视图时,顶层视图所基于的视图和各级视图使用的 Visual FoxPro 基表将出现在“数据工作期”窗口中,远程表不会出现在“数据工作期”窗口中。
通过创建基于本地视图和远程视图的新本地视图,可以在一个视图中集成本地数据与远程数据。
若要创建集成本地数据与远程数据的视图
- 或者 -
例如,可以使用如下代码创建一个集成了本地 Employee 表与远程 Orders 表中信息的本地视图:
OPEN DATABASE testdata
CREATE SQL VIEW remote_orders_view ;
CONNECTION remote_01 ;
AS SELECT * FROM orders
CREATE SQL VIEW local_employee_remote_orders_view ;
AS SELECT * FROM testdata!local_employee_view, ;
testdata!remote_orders_view ;
WHERE local_employee_view.emp_id = ;
remote_orders_view.emp_id
在多级视图中更新数据时,更新将向下延续一层视图。如果要更新多级视图的基表,则必须为多级结构中的每一个视图都发送一条 TABLEUPDATE 命令。
经常需要将一些数据从主数据库中分离出来进行显示、收集或修改。Visual FoxPro 相应的提供了可用自由数据的功能,使用这种功能,可以用与主数据库相连的视图建立数据的子集,这样就脱离主数据库对自由数据进行操作。可以直接访问视图,也可通过应用程序访问。过后,还可以将数据上载回主数据库。
在下面这些情况下,可使用自由数据:
处理游离视图
可用下列函数或命令创建和使用游离视图数据:
如果要在创建游离视图的计算机以外的机器上使用此视图,必须在这台机器(目标机)上建立主数据库文件(.dbc)的副本:确认目标机上的视图使用了 ODBC 数据源;并分析数据需求以决定所需的视图内容。
注释 可使用 ODBC 管理器在机器上安装数据源。从 Visual FoxPro 程序组或控制面板都可访问 ODBC 管理器程序。
和自由数据一样,在创建游离视图前,分析需求以决定需要用于游离数据库中的视图结构。确定了脱机使用的数据子集之后,就可使用已有的视图或是创建新视图。如果已有视图返回的记录正是您脱机操作时想要的,可直接使用它,否则需要以编程方式创建视图。游离视图中包含的数据存储在本地机数据库中的一个 .dbf 文件中。
注释 如果要在游离视图中修改数据,则要在使之游离前确认视图可更新。由于视图是游离的,只能以编程方式设置它的更新属性;不能在“视图设计器”中修改游离视图。
若要使用已有的游离视图
例如,如果要在客户机上更新帐目,添加客户,及记录新的销售,需要当前订单和联机产品资料以及客户信息。就可以建立一个称为 customerinfo
的视图,组合了来自于 Customer 表、Order 表和 Orderitems 表的信息。可用下列代码创建视图:
CREATEOFFLINE("customerinfo")
以编程方式创建游离视图
例如,以下代码创建一个游离视图,用于显示来自联机数据库中 Products
表和 Inventory
表中的数据。由于没有指定更新条件,因此视图是只读的。
CREATE SQL VIEW showproducts ;
CONNECTION dsource ;
AS SELECT * FROM Products INNER JOIN Inventory ;
ON Products.ProductID = Inventory.ProductID ;
CREATEOFFLINE("showproducts")
为自由数据创建了视图后,就可在应用程序中象使用其他视图一样使用这些视图:添加、修改和删除记录。多个用户能够以共享模式同时访问同一数据库中的游离视图。另外,如果不想保留对自由数据的任何修改,可以恢复信息重新反映原始信息。
使用游离视图,可以象使用联机视图那样使用表单、报表或应用程序来显示和更新数据。例如,以下代码打开 Showproducts
视图:
USE Showproducts
提示 如果在游离视图中没有得到所需的数据子集,请检查远程视图的优化设置。如果使用 DBSETPROP( ) 函数设置了 MaxRecords 属性,则视图中最多只能包含设置的记录数。如果在视图的字段列表中包含一个备注字段,则即使 FecthMemo 设置为否(.F.),该备注字段也将自动包含在结果集合中。
在一些情况下,尤其在多用户环境中,很多人同时操作相同的数据。在把自由数据更新到源数据库之前,可能希望检查一下那些被改动过的数据。使用带有 ADMIN 子句的 USE 命令,可以查看对自由数据的所有修改,还可以有选择地放弃一些还没有与数据源相连的那些修改。例如,以下代码以管理员模式打开 Showproducts
视图。
USE Showproducts ADMIN
处理完自由数据后,就可以更新服务器中的数据了,更新方法是使用同一表来更新经常使用自由数据的事务处理。在处理远程数据时,请注意:
在进行更新之前,需要用 USE 命令和 ONLINE 关键字重新与主机数据库连接。在发出命令后,Visual FoxPro 用存储在视图中的数据源信息确定主机数据库的位置。连接建立后,可用 TABLEUPATE( ) 函数处理自由数据中的更新。
为了确保连接信息的正确,而不用考虑主机或视图表的位置,需要使用连接字符串语法,而不是命名的连接。
要处理对本地表的批量修改,可使用人工事务处理,它允许在一个事务处理中(而不是一系列单独的事务中分别处理)处理整批记录。
用游离视图更新本地表
代码 | 注释 |
|
重新连接到主数据库并打开视图 |
|
检查更新冲突并进行适当的更新 |
处理对远程表的批量修改,使用人工事务处理:从 TABLEUPDATE( ) 开始,以 SQLCOMMIT( ) 或 SQLROLLBACK( ) 结束过程。
为了设置连接以可用人工方式地管理事务处理,需要对视图临时表使用 CURSORGETPROP( ) 函数以得到连接句柄,然后设置手动模式的 Transaction 属性。
在以下代码中,视图 myview
的当前连接标识存储在 hConn1
中。hConn1
将 Transaction 属性设为“2”— 人工事务处理。
hConn1 = CURSORGETPROP("CONNECTHANDLE","myview") ;
SQLSETPROP(hConn1,"TRANSACTIONS",2)
设置了连接以处理更新之后,可用 TABLEUPDATE( ) 函数处理事务。
如果主数据库保存在在远程服务器上,例如 SQL 服务器,可将以下代码作为指导。
用游离视图更新远程表
代码 | 注释 |
|
重新连接到主数据库并打开视图 |
|
设置视图连接为人工处理事务 |
|
处理更新和更新冲突 |
如果要更新单独一行,可使用自动事务处理。因为每个进行更新的语句,删除或插入的语句都以独立的事务进行处理,不可能重新运行前面的事务处理。
USE customerview ONLINE EXCLUSIVE GO TO 3 IF TABLEUPDATE (0, .F. workarea) *
处理冲突代码ENDIF
提示 可用 GETNEXTMODIFIED( ) 函数更新本地表中的单独一行。
如果决定删除自由数据并恢复联机视图,可使用 DROPOFFLINE( ) 函数。
若要取消自由数据更新
注意检查返回值。真(.T.)表明成功,假(.F.)表明在命令发出前,视图没有关闭。
以下代码放弃对 myview
视图中数据子集的全部修改。视图仍是数据库部分,但放弃了当前的数据。
DROPOFFLINE("myview")
可以删除自由数据,但不能对游离视图使用 PACK、ZAP 或 INSERT 命令。
通过设置视图属性,可以优化视图性能。
通过视图和活动视图临时表的 FetchSize 属性,可以控制每次递增地从远程数据源所取的数据行数量。属性的设置可以利用 DBSETPROP( ) 和 CURSORSETPROP( ) 函数来完成。
利用 Visual FoxPro 延迟获取备注字段的功能,可以加速视图数据的检索。在选择了延迟获取备注字段这一功能之后,Visual FoxPro 将不检索备注字段的内容,而是等到您选择了打开并显示这一字段时才检索。因为 Visual FoxPro 需要关键字段和表名来定位在远程数据源上的数据行,所以若要实现延迟获取备注字段,必须设置 UpdateName 或 UpdatableFieldList 属性,KeyField 或 KeyFieldList 属性以及 Tables 属性。但是并不需要设置 SendUpdates 或 Updatable 属性为 on 状态。
可以通过设置属性来控制打开视图时下载的数据量。当向 Visual FoxPro 数据源发送一条 SQL 语句来创建视图时,数据源将建立并保存一个结果集合,MaxRecords 属性将指定从远程结果集合取入视图的最大行数。默认的设置为 - 1,即下载结果集合的全部数据行。
若要控制下载至视图的数据行数
- 或者 -
例如,下面的代码将修改视图定义,限制下载至视图的数据行数目最多为 50,而不考虑远程数据源上得到的结果集合大小:
OPEN DATABASE testdata
USE VIEW remote_customer_view
?DBSETPROP ('Remote_customer_view', ; 'View','MaxRecords', 50)
使用 CURSORSETPROP( ) 函数,可以为一个活动视图设置 MaxRecords 属性。
提示 因为 MaxRecords 不能控制结果集合的创建,所以不能用 MaxRecords 属性来中止一个已运行的查询。可以使用 QueryTimeOut 属性来控制在远程数据源的执行时间。
如果要优化视图或查询,则需要了解执行计划:评估联接和过滤器子句的顺序。用 SYS(3054) 函数,可显示三级 Rushmore 优化中的其中之一。三个等级是指过滤器条件或联接条件可使用 Rushmore 优化的程度。三个等级分别是全部 (Full),部分 (Partial),完全不 (None)。
若要显示过滤器的执行计划
例如,可键入:
SELECT * FROM customer, orders ;
AND Upper(country) = "MEXICO"
这个例子中,屏幕显示:
Using Index Tag Country to optimize table customer
Rushmore Optimization Level for table customer: Full
Rushmore Optimization level for table orders: none
然后,就能将 11 传给 SYS 函数以计算 FORM 和 WHERE 子句中联接。
若要显示联接的执行计划
例如,可键入:
SELECT * ;
FROM customer INNER JOIN orders ;
ON customer.cust_id = orders.cust_id ;
WHERE Upper(country) = "MEXICO"
例如,屏幕显示:
Using Index Tag Country to optimize table customer
Rushmore Optimization Level for table customer: Full
Rushmore Optimization level for table orders: none
Joining table customer and table orders using Cust_id
如果联接的执行方案不符合指定要求,可强行使联接完全按所写的执行,而不用处理器优化。若要强行指定联接的结果顺序,需要添加 FORCE 关键字,并将联接条件加入 FROM 子句中。WHERE 子句中的联接条件不包括在强制联接结果中。
注释 不能在 SQL pass-through 语句或远程视图中使用 FORCE 关键字,因为此关键字是 Visual FoxPro 的 ANSI 标准扩展,其他的 SQL 字典不支持它。
FORCE 子句是全局子句,因此适用于 JOIN 子句中的所有表。保证了联接表的显示顺序就是它们联接的顺序。圆括号可用于控制联接的结果顺序。
在此例中,指定的第一个联接也是结果的第一个联接。Customer 表首先与 Orders 表相联接。联接的结果再与 OrdItems
表联接。
SELECT * ;
FROM FORCE Customers ;
INNER JOIN Orders ;
ON Orders.Company_ID = Customers.Company_ID ;
INNER JOIN OrItems;
ON OrdItems.Order_NO = Orders.Order_NO
在此例中,首先计算圆括号中 Orders
表和 OrdItems
表的联接,再计算联接的结果与 Customers
表的联接。
SELECT * ;
FROM FORCE Customers ;
INNER JOIN (orders INNER JOIN OrdItems ;
ON OrdItems.Order_No = Orders.Order_No) ;
ON Orders.Company_ID = Customers.Company_ID
通过共享连接,可以使一个活动连接成为多个远程视图的信息通道。通过共享活动连接,您可以:
可以对视图定义进行设置,使其在激活时使用共享连接。在使用该视图时,Visual FoxPro 将使用已有的共享连接(如果存在)与远程数据源相连。如果没有正在使用的共享连接,Visual FoxPro 将在视图打开时,创建唯一的连接,这个连接可在以后被其他视图共享。
在一个 Visual FoxPro 工作期中,只有一个命名连接的活动实例被共享。如果一个连接有多个活动实例,则第一个用作共享连接的实例成为指定的共享连接。对于所有使用该连接定义并采用共享连接的视图,可以通过指定的共享连接来访问远程服务器。
指定共享连接以外的连接不被共享。共享连接的作用范围不限于工作期。
若要共享一个连接
- 或者 -
- 或者 -
下面的代码创建一个视图,在使用 USE 命令激活此视图时,共享一个连接:
CREATE SQL VIEW product_view_remote ;
CONNECTION remote_01 SHARE AS ;
SELECT * FROM products
USE product_view_remote
当连接繁忙的时候(比如,当 Visual FoxPro 正在获取数据放入临时表时),您可能不希望在同一连接上开始另外一个抓取数据操作或发送更新信息,这时可以使用 ConnectBusy 属性来判断一个连接是否繁忙。当连接繁忙时,它返回“真”(.T.)。您可以在应用程序中使用此属性,在准备向远程数据源发送某一请求之前,测试连接是否繁忙。
若要判断连接是否繁忙
使用 SQLGETPROP( ) 函数时需要连接句柄,可以利用 CURSORGETPROP( ) 函数的 ConnectHandle 属性为一个活动视图取得连接句柄。下面的代码先取得一个连接句柄,然后使用该句柄来测试连接是否繁忙:
nConnectionHandle=CURSORGETPROP('ConnectHandle')
SQLGETPROP(nConnectionHandle, "ConnectBusy")