中级SQL说明
通过了解中级结构化查询语言的一些概念,用户可以增强控制数据库的结构和对象的能力,并且可以通过许多有趣的和强有力的途径操纵这些机构中包含的数据。结合使用诸如DAO和ADO之类的数据访问方法,中级SQL
可以很大程度的提高用户应用程序的灵活性及其表现。
基础、中级和高级SQL的不同点
在基础、中级和高级SQL之间划分一条明显的界限并不是一件容易的事情,在很多情况下,决定其所属都只是简单的决断。但是对于该系列在Access
2000中使用SQL的文章来说,还考虑了如下的一些方面:
首先一点在于SQL语句本身的复杂级别。在前面的文章中,我们努力使用那些常用的语句,而且是最简单的形式。本文则在前面基础篇的基础上介绍了更复杂的语句。
其次是在Access
2000中已经包含了一些新的SQL语句、子句和关键词。尽管在本文中仍将使用Access上一版本中所包含的SQL语句,但是一定会出现一些在Access中第一次出现的SQL语句,在高级SQL一文中也是如此。
最后,那些关于安全性和多用户解决方案的SQL语句将在高级篇中介绍,因为这些语句常常是用于更复杂的应用程序中的
通过使用中级SQL,用户可以为你的Access应用程序增加更强的灵活性和能力。尽管简单的和直接的SQL语句能够完成很多的事情,但是使用更复杂的语句将扩展在数据库中访问和处理信息的方法范围。使用中级SQL也将使得用户可以更好的控制你的数据库使用和维护工作
增强SQL
在Access
2000中,为了支持Access的新特性,为了和ANSI-92的标准更加一致,并且允许在Access
和 Microsoft? SQL Server?间的更好的兼容性,包含在Microsoft
Jet
4.0数据引擎中的SQL作了许多增强。Jet数据引擎现在有两种格式的SQL语法:一种是支持以前使用的SQL语法,另一种是支持新的SQL语法规范。需要格外注意的是,只有在用户使用ActiveX?
Data Objects (ADO)和Jet OLE DB
provider时新的语法才是可用的,而当前通过Access SQL
View接口或者DAO是无法使用新的语法的。本文指出只有通过Jet
OLE DB provider 和 ADO才能够使用某个特定的SQL命令。
在Access的上一版本中,数据访问对象(DAO)是主要的数据访问方法。而现在发生了改变,尽管DAO
仍旧被支持,但新的数据访问方法是使用ADO。ADO是微软的通用数据访问战略(Microsoft's
Universal Data Access
strategy)的一部分,其最基本的假设是无论数据存在那里都是可以访问的,不管是数据库、目录结构还是某重用户自定义的数据库。
在讨论Microsoft Jet SQL
时,ADO是非常重要的,正如在前面提到的,一些新的SQL语句只有在使用ADO
和Jet OLE DB
provider时才是可用的。在本文和与本文相配套的示范数据库中,所有的代码都是使用ADO些的。那些没有特意指明为只有通过ADO才可用的SQL语句都可以通过Access
SQL View 用户接口或
DAO来执行。详尽的关于ADO的讨论超出了本文的范围,用户可以在下面的网站中找到最近的信息
http://www.microsoft.com/data/ado/
SQL代码规范
本文使用一致性的SQL代码规范。与所有的代码规范相同,目的是使用易读和易于理解的方式来显示代码。这就要通过空格、换行和大写关键字的结合使用来实现。通常来说,要使用大写字母来打印SQL的关键字,如果SQL语句必须换行,尽量使SQL语句的主要部分一起换行。看过一些例子之后,相信读者会对此有较好的感觉。
不合格式的SQL代码
CREATE TABLE tblCustomers (CustomerID INTEGER NOT NULL, [Last Name]
TEXT(50) NOT NULL, [First Name] TEXT(50) NOT NULL, Phone TEXT(10),
Email TEXT(50))
良好格式的SQL代码
CREATE TABLE tblCustomers (
...CustomerID INTEGER NOT NULL,
...[Last Name] TEXT(5) NOT NULL,
...[First Name] TEXT(50) NOT NULL,
...Phone TEXT(10),
...Email TEXT(50))
改变数据表
在建立或倒入一个数据表之后,用户可能需要修改表的设计。这时就可以使用ALTER
TABLE语句。但是注意,改变现存的表的结构可能会导致用户丢失一些数据。比如,改变一个域的数据类型将导致数据丢失或舍入错误,这取决于用户现在使用的数据类型。改变数据表也可能会破坏用户的应用程序中涉及到所改变的域的部分。所以用户在修改现有表的结构之前一定要格外小心。
使用ALTER TABLE
语句,用户可以增加,删除或改变列或域,也可以增加或删除一个约束。还可以为某个域设定缺省值,但是一次只能修改一个域。假设我们有一个记账单的数据库,而我们想在顾客数据表中增加一个域,这时可以使用ALTER
TABLE 语句,在其ADD COLUMN
子句后写上域的名称、数据类型和数据的大小(如果需要的话)。
ALTER TABLE tblCustomers
ADD COLUMN Address TEXT(30)
要改变域的数据类型或大小,可以使用ALTER
COLUMN子句,在后面加上期望的数据类型和数据的大小。
ALTER TABLE tblCustomers
ALTER COLUMN Address TEXT(40)
如果需要改变域的名称,则必须删除该域并重新创建。删除一个域要使用DROP
COLUMN 子句,在其后跟上域的名称。
ALTER TABLE tblCustomers
DROP COLUMN Address
注意使用这种方法将会删除该域的现存数据。如果需要保存这些数据,则用户需要在Access的用户界面的设计模式中改变该域的名称,或者编写代码将现存的数据保存在一个临时的表中然后将其添加到改名后的表中。
缺省值是指在表中增加新纪录并且没有为该列赋值时自动填充到该域中的值。为某域设置缺省值,要在定义域的类型后使用使用DEFAULT关键字,不管是使用ADD
COLUMN或 ALTER COLUMN 子句。
ALTER TABLE tblCustomers
ALTER COLUMN Address TEXT(40) DEFAULT Unknown
注意缺省值并不使用单引号包含,如果用了单引号,则引号也会插入到记录中。在CREATE
TABLE语句中也可以使用DEFAULT关键字。
CREATE TABLE tblCustomers (
CustomerID INTEGER CONSTRAINT PK_tblCustomers
PRIMARY KEY,
[Last Name] TEXT(50) NOT NULL,
[First Name] TEXT(50) NOT NULL,
Phone TEXT(10),
Email TEXT(50),
Address TEXT(40) DEFAULT Unknown)
注意: DEFAULT 语句只有在Jet OLE DB
provider和ADO中可以执行,在Access SQL
View的用户界面中使用将会返回错误信息。
下面的部分将讨论如何在ALTER
TABLE语句中使用约束。要获得更详细的有关ALTER
TABLE的说明,请在Office 助手中或在Microsoft Access
帮助的回答向导的标签页中输入ALTER TABLE
,然后单击查找。
约束
在《Access 2000的基础Microsoft Jet
SQL》一文中,我们讨论了建立表之间的联系的约束方法。约束也能用于建立主键和参考完整性,来限制插入到一个域中的数据值。通常,约束可以用于保持用户数据库中的数据完整性和一致性。
共有两种类型的约束:单数据域(或称域级的)的约束和多数据域(或称表级的)的约束。两种约束都可以用在CREATE
TABLE 或 ALTER TABLE 语句中。
单域的约束,也就是通常所说的列级的约束,是在域及其数据类型定义后针对该域定义的。下面我们使用用户表,在CustomerID域生成一个单域的主键。增加约束时,在域名后使用CONSTRAINT关键字。
ALTER TABLE tblCustomers
ALTER COLUMN CustomerID INTEGER
CONSTRAINT PK_tblCustomers PRIMARY KEY
注意这里给出了约束的名称。用户还可以在定义主键时使用简称而省略CONSTRAINT子句。
ALTER TABLE tblCustomers
ALTER COLUMN CustomerID INTEGER PRIMARY KEY
然而,使用简称的方法将导致Access随机的生成约束的名称,从而使得在代码中难以引用。所以,最好给约束制定名称。
要删除一个约束,可以在ALTER TABLE 语句中使用DROP
CONSTRAINT 子句,并给出约束的名称。
ALTER TABLE tblCustomers
DROP CONSTRAINT PK_tblCustomers
约束还可以用来给域限制允许值。用户可以将限制值设为非空(NOT
NULL)或唯一(
UNIQUE),或者定义一个检验性的约束,该约束指一种可以应用于某个域的规则。比如用户希望限制姓和名的域是唯一的,就意味着在表中永远不会有两个相同姓名的记录存在。这是因为这种约束是多域的性的,是在表的级别定义的,而非域的级别。使用ADD
CONSTRAINT子句可以定义一个多域的列表。
ALTER TABLE tblCustomers
ADD CONSTRAINT CustomerNames UNIQUE
([Last Name], [First Name])
注意:
我们在这里只是示范一下如何使用约束,而在实际的应用程序中,用户可能并不希望彻底限制姓名的唯一性。
检验性约束是一种新的强有力的SQL特性,它通过一个表达式从而允许用户在表中添加数据合法性检验,该表达式可以指向一个单域,也可以指向跨越一个或多个表的多个域。比如用户希望确定输入到发票记录中的数值是否总是大于0,则可以在ALTER
TABLE语句的ADD CONSTRAINT子句中定义一个CHECK关键字。
ALTER TABLE tblInvoices
ADD CONSTRAINT CheckAmount
CHECK (Amount > 0)
注意: 检验性约束语句只能通过Jet OLE DB
provider和ADO来执行,在Access SQL
View的用户界面中使用将返回错误信息。而且,要删除一个检验性约束,也必须在Jet
OLE DB provider 和ADO中执行DROP
CONSTRAINT语句。另外,如果用户已经定义了一个检验性约束:
(1)
在Access的用户界面中并不会显示为一个合法性规则,(2)
用户也不能在该界面中定义合法性文本的属性,否则将给出一般性错误信息,(3)
在用户通过ADO使用DROP
CONSTRAINT语句之前,不能够通过Access的用户界面或者在代码中删除数据表。
用来定义一个检验性约束的表达式也可以用来指向同一个表中的多个域,甚至是其他表中的域。其中可以使用任何在Microsoft
Jet SQL 中合法的操作符,比如SELECT
语句、数学运算符、以及集合函数等。用来定义检验性约束的表达式的长度不能超过64个字符。
设想用户希望在将顾客加入到Customers
表之前检查每个顾客的信用额度。则可以使用带有ADD
COLUMN 和CONSTRAINT 子句的ALTER TABLE
语句生成一个约束,该约束将查找在CreditLimit表中的值来验证顾客的信用额度。下面的SQL语句将生成一个tblCreditLimit
表,然后将CustomerLimit域加入到tblCustomers
表中,并将检验性约束加到tblCustomers表,最后对该检验性约束进行测试。
CREATE TABLE tblCreditLimit (
Limit DOUBLE)
INSERT INTO tblCreditLimit
VALUES (100)
ALTER TABLE tblCustomers
ADD COLUMN CustomerLimit DOUBLE
ALTER TABLE tblCustomers
ADD CONSTRAINT LimitRule
CHECK (CustomerLimit )和小于( ANY
(SELECT CustomerID FROM tblInvoices)
当我们想在主查询中检索满足子查询比较条件的所有记录时使用谓词ALL。
SELECT *
FROM tblCustomers
WHERE CustomerID > ALL
(SELECT CustomerID FROM tblInvoices)
EXISTS子查询
EXISTS谓词是用于子查询来在一个结果集中检查所以存在值的记录。换句话说,就是如果子查询没有返回任何行,这个比较就False。而如果它返回了一行或多行,这个比较就为True。
SELECT *
FROM tblCustomers AS A
WHERE EXISTS
(SELECT * FROM tblInvoices
WHERE A.CustomerID = tblInvoices.CustomerID)
注意在前面的SQL 语句里, tblCustomers
工作表使用了一个别名。这就是为何我们可以在后来的子查询中引用它的原因。当一个子查询以这种格式与一个主查询联接时就称相关查询。
通过使用NOT逻辑操作符,我们可以检索和EXISTS子查询相反的记录,从而可以得到所有没有任何发票的顾客的结果集。
SELECT *
FROM tblCustomers AS A
WHERE NOT EXISTS
(SELECT * FROM tblInvoices
WHERE A.CustomerID = tblInvoices.CustomerID)
如果你想得到更多的关于子查询的信息,在Office
助理或微软Access帮助窗体的Answer Wizard标志中输入SQL
subqueries ,并单击Search。
连接
在一个如同Access的相关数据库系统中,你会常常需要同时从多个工作表中摘出信息记录。这可以通过使用一个SQL
JOIN语句来实现。JOIN语句可以让你从已经定义了相互关系的工作表中检索记录,而不用管记录和工作表之间的关系是一对一、一对多还是多对多。
内部连接
内部连接,也被理解为对等连接,就是被使用的连接里最一般的形式。这种连接通过匹配一个各个工作表中共有的域值来从两个或更多的工作表中检索记录。你所连接的域必须具有类似的数据类型,但你就不能对MOMO和OLEOBJECT数据类型进行连接。为了建立一个INNER
JOIN语句,在SELECT语句的FROM子句里使用INNER
JOIN关键字。让我们使用INNER JOIN
建立所有拥有发票的顾客的结果集,并带上那些发票的时间和金额。
SELECT [Last Name], InvoiceDate, Amount
FROM tblCustomers INNER JOIN tblInvoices
ON tblCustomers.CustomerID=tblInvoices.CustomerID
ORDER BY InvoiceDate
注意工作表名被INNER
JOIN关键字所分开,并且相关的比较是在ON关键字的后面。对于相关的比较,你也可以使用、
=或
操作符,并且你也可以使用BETWEEN关键字。同时注意各个工作表只在比较关系中使用的ID域,它们都不是最后结果集的组成。
如果要进一步的限制SELECT
语句我们可以在ON子句中的比较连接后面使用WHERE子句。在下面的例子中我们通过只包括1998年1月1日以后的发票来缩小结果集。
SELECT [Last Name], InvoiceDate, Amount
FROM tblCustomers INNER JOIN tblInvoices
ON tblCustomers.CustomerID=tblInvoices.CustomerID
WHERE tblInvoices.InvoiceDate > #01/01/1998#
ORDER BY InvoiceDate
在希望连接多个工作表的案例中,你可以嵌入INNER
JOIN子句。在这个例子里,我们将在过去的一个SELECT语句的基础上产生我们的结果集,但我们也将通过为tblShipping工作表添加INNER
JOIN使结果包括每个顾客的所在城市和国家。
SELECT [Last Name], InvoiceDate, Amount, City, State
FROM (tblCustomers INNER JOIN tblInvoices
ON tblCustomers.CustomerID=tblInvoices.CustomerID)
INNER JOIN tblShipping
ON tblCustomers.CustomerID=tblShipping.CustomerID
ORDER BY InvoiceDate
注意第一个JOIN子句为圆括号所包含以使之从逻辑上和第二个JOIN子句分开。而在FROM子句中使用一个第二个工作表的别名把一个工作表连接到自身也是可能的。让我们假设我们想找到所有具有相同的名的顾客记录。我们可以通过为第二个工作表创建一个别名“A”并查找其姓氏不同的记录来实现。
SELECT tblCustomers.[Last Name],
tblCustomers.[First Name]
FROM tblCustomers INNER JOIN tblCustomers AS A
ON tblCustomers.[Last Name]=A.[Last Name]
WHERE tblCustomers.[First Name]A.[First Name]
ORDER BY tblCustomers.[Last Name]
外部连接
外部连接是在当记录保存在某一个工作表中时用于在多个工作表进行记录检索,即使在其它的工作表中没有匹配的记录也行。Jet
数据库引擎共支持两种类型的外部连接。考虑两个互相相近的工作表,一个在左边,另一个在右边。左外部连接将在右工作表中选择所有匹配比较关系标准的所有行和左工作表中的所有行,即使在右工作表中没有匹配记录存在。而右外部连接则是左外部连接的简单反转;即所有在右工作表中的行将被保存。
作为一个例子,让我们假设我们想测定每个顾客的所有发票数量,但如果一个顾客没有发票,我们希望通过消息“NONE”来显示其信息。
SELECT [Last Name] & ', ' & [First Name] AS Name,
IIF(Sum(Amount) IS NULL,'NONE',Sum(Amount)) AS Total
FROM tblCustomers LEFT OUTER JOIN tblInvoices
ON tblCustomers.CustomerID=tblInvoices.CustomerID
GROUP BY [Last Name] & ', ' & [First Name]
在前面的SQL语句中仍然有几个问题。第一个是对字符串连接操作符“&”的使用,这个操作符允许你把两个或更多的域连接到一起组成一个字符串。第二个是
immediate
if(IIF)语句,它会检查合并后的字符串是否为空。如果为空,这个语句将返回消息“NONE”,而如果组合不是空,将返回组合后的值。最后一点是外部连接子句。使用左外部连接保存左工作表的行从而让我们可以看到所有的顾客,包括那些没有发票在帐目中的。
在一个多工作表的连接中外部连接可以被嵌套在内部连接里,但内部连接不可以被嵌套在外部连接中。
笛卡儿乘积
当我们讨论联接时常常遇到的一个术语是笛卡儿乘积。笛卡儿乘积的定义为“把所有表单的所有行完全合并”。例如,如果你想不用任何约束把两个工作表联合在一起,你就完成了一个笛卡儿乘积。
SELECT *
FROM tblCustomers, tblInvoices
这不是一个好东西,特别当你要处理的工作表中包含有成百上千行数据时。所以你应该通过约束你的连接来避免笛卡儿乘积。
The UNION operator
虽然UNION
的操作也可以视为一个合并查询,但我们不可以技术性地把它看作是一个联接,它之所以被提到是因为它能把从多个来源获得的数据合成一个结果表单中,而这一点和某些类型的联接是类似的。UNION
操作一般被用来把来自表单、SELECT语句或查询的数据结合,并省略掉任何重复的行。所有的数据源必须有相同数目的域,不过这些域不一定要是相同的数据类型。让我们假设我们有一个雇员表单,其中具有和顾客工作表单相同的结构,那么我们希望合并这两个工作表得到一个姓名和电子邮件地址信息的列表。
SELECT [Last Name], [First Name], Email
FROM tblCustomers
UNION
SELECT [Last Name], [First Name], Email
FROM tblEmployees
如果你希望找到这些表中的所有域,我们可以使用TABLE关键字,如同下面一样:
TABLE tblCustomers
UNION
TABLE tblEmployees
UNION操作不会显示任何在两个表单中重复出现的记录,但它可以通过在UNION关键字后使用谓词ALL来覆盖重复信息,如下所示:
SELECT [Last Name], [First Name], Email
FROM tblCustomers
UNION ALL
SELECT [Last Name], [First Name], Email
FROM tblEmployees
转换语句
虽然转换语句也可以视为一个交叉表查询,但我们不可以技术性地把它看作是一个联接,它之所以被提到是因为它能把从多个来源获得的数据合成一个结果表单中,而这一点和某些类型的联接是类似的。
TRANSFORM
语句通常用于计算总数、平均值、数目以及其它对记录进行总体统计的算法。并在计算后把结果信息显示在一个格子或数据表中,其中的数据分别按照行和列排列。一个TRANSFORM
语句的一般形式如下:
TRANSFORM aggregating function
SELECT Statement
PIVOT column heading field
我们假设我们可以建立一个按照每一年为基础显示每个顾客的所有发票的数据表。这个列名应该是顾客的姓名,而行名则将是年份。让我们修改原来的SQL语句以符合转变后的语句.
TRANSFORM
IIF(Sum([Amount]) IS NULL,'NONE',Sum([Amount]))
AS Total
SELECT [Last Name] & ', ' & [First Name] AS Name
FROM tblCustomers LEFT JOIN tblInvoices
ON tblCustomers.CustomerID=tblInvoices.CustomerID
GROUP BY [Last Name] & ', ' & [First Name]
PIVOT Format(InvoiceDate, 'yyyy')
IN ('1996','1997','1998','1999','2000')
注意SUM函数是合计函数,组里的列的题头用在SELECT
语句的子句里,而行的名字由PIVOT关键字后所列出的域名决定。
如果你想知道关于连接的更多信息,在Office
助理或微软Access帮助窗体得Answer Wizard标志中输入SQL
joins,并单击Search。
在Access中使用中级SQL
现在我们已经讨论了中级SQL的语法,那么让我们看看在一个Access应用程序中我们可以使用它的一些途径。
数据库范例
作为这篇文章的附带,这里有一个叫acIntSQL.mdb的数据库范例。
在acIntSQL中的任一处都是基于本文所提到的所有主题,并且它通过查询和范例的代码演示了我们所讨论的不同SQL语句。
在acIntSQL中所使用到的许多部分查询都是基于特定工作表中存在和包含的数据,或者是基于其它已经存在的数据库对象。如果你由于丢失数据而在运行一个查询产生故障,打开工作表重置窗体并单击工作表重置按键。这将会重新生产工作表和其中原始缺省数据。如果要手动通过工作表重置过程,你需要按照下面的顺序执行这些查询过程:
Drop Table Shipping
Drop Table Invoices
Drop Table Customers
Drop Table CreditLimit
Create Table Customers
Create Table Invoices
Create Table Shipping
Create Table CreditLimit
Populate Customers
Populate Invoices
Populate Shipping
Populate CreditLimit
查询
查询就是指存储在Access数据库中并可以随时调用的SQL
语句,也可以直接被Access 用户界面或Visual Basic? for
Applications (VBA)编程语言调用。查询可以使用Access Query
Designer来建立,Access Query
Designer时一个可以很容易建立SQL语句的强大的可视化工具。或者你也可以通过直接在SQL视图窗口输入SQL语句来建立查询。
如同在"Microsoft Jet SQL for Access 2000基础篇"一文中所述,
Access把数据库中所有面向数据的任务转化为SQL
语句。要演示这一点,让我们使用Access Query
Designer来建立一个查询。
打开acIntSQL数据库。
(单击此处拷贝acIntSQL.mdb 数据库例子。)
确保tblCustomers 和
tblInvoices这两个表单已经创建并且其中包含有数据。
在数据库窗口中从Objects条中选择Queries选项。
在数据库窗口工具条里单击按键 New。
在New Query对话框中选择Design View并单击OK。
在Show
Table对话框中选择tblCustomers并单击Add;接着选择tblInvoices
并单击Add;接着单击Close按键。
在tblCustomers 域名列表中选择Last Name
域并把它拖到设计表格中的第一个域中。
在tblInvoices 域名列表中选择InvoiceDate 和
Amount域并把它们拖到设计表格中。
在设计表格中InvoicwDate域的Sort属性里选择Ascending。
从Access菜单条中选择View并单击SQL
View。这样就打开了SQL View
窗口和显示了在查询中Access正在使用的SQL语法。
注意 这个查询类似于存储在acIntSQL 数据库中的"Join -
Inner"查询。
嵌入语句
嵌入SQL 语句就是指你在Visual Basic for Applications (VBA)
编程语言中使用SQL
语句。虽然深入讨论如何使用VBA超出了本文的范围,但如何使用程序来运行SQL
语句却是一件简单的工作。
在acIntSQL数据库中,有两个使用内部SQL语句的窗体需要通过Jet
OLE DB provider 和 ADO来运行:就是演示数据定义语句的
Intermediate DDL 窗体,以及演示数据处理语句的Intermediate
DML窗体。
中级DDL 语句
这个acIntSQL数据库有许多关于你可以用来管理你的数据库结构的SQL
语句的范例。有一部分数据定义语言 (DDL)
语句被以数据定义查询的方式存储。而其它的则在程序设计代码的内部作为内联SQL使用。如果你要使用这些DDL例子,你需要在运行它之前删除一些数据库对象。例如,如果你想运行创建当前数据类型的查询,你就先要确定当前数据表单不存在。如果不是,那么,这个查询就会返回一个信息告诉你这个表单已经存在。在运行任何DDL
例子之前,检查它所要创建或改变的数据库对象确定其已经被设定好,这样程序才能完全的运行。
在内联DDL
语句范例中,同样的建议仍然是适用的:检查并设定它们会影响的数据库对象以确保DDL
语句的顺利运行。
一般来说,内联DDL 语句只是通过简单设定一个ADO
Connection对象来运行,并将SQL 语句传送给
Connection对象的运行程序。下面是来源于在中级DDL语句窗体的二进制数据类型的输入输出。
Private Sub cmdBinary_Click() Dim conDatabase As ADODB.Connection
Dim SQL As String
On Error GoTo Error_Handler
Set conDatabase = Application.CurrentProject.Connection
'注意: Fields 1 through 4 can be created through both
'SQL View and the Jet OLEDB Provider.
'Fields 5 and 6 can only be created through the
'Jet OLE DB provider.
SQL = "CREATE TABLE tblCodeBinaryDataTypes (" & _
"Field1_BINARY BINARY, " & _
"Field2_BINARY250 BINARY(250), " & _
"Field3_VARBINARY VARBINARY, " & _
"Field4_VARBINARY250 VARBINARY(250), " & _
"Field5_BVARYING BINARY VARYING, " & _
"Field6_BVARYING250 BINARY VARYING(250))"
conDatabase.Execute SQL
MsgBox "The BINARY datatypes table has been created!"
conDatabase.Close
Set conDatabase = Nothing
Exit Sub
Error_Handler:
MsgBox Err.Description, vbInformation
End Sub
运行过其中一个DDL
语句后,在设计视图中打开被影响的数据库查看产生了什么变动。如果DDL
语句影响了表单之间的关联,打开编辑关联窗口查看其变动。例如让我们检查一下在中级DDL语句窗体中的Alter
Table w/ Fast Foreign Key输出指令和按键。
打开acIntSQL 数据库。
确定tblCustomers 和 tblInvoices 表单已经被创建。
在数据库窗口从Objects条中选择Forms。
在数据库窗口工具条中着重显示Intermediate DDL
语句的窗体并单击Design按键。
在Intermediate DDL 语句窗体中,鼠标右键点击Alter Table w/
Fast Foreign Key按键并从弹出菜单中选择 Build
Event…。这操作将打开VBA开发环境以及包含着cmdFastKey_Click子过程的代码窗口。
检查被分配给 SQL变量的SQL 语句。
SQL = "ALTER TABLE tblInvoices " & _
"ADD CONSTRAINT FK_tblInvoices " & _
"FOREIGN KEY NO INDEX (CustomerID) REFERENCES " & _
"tblCustomers (CustomerID) " & _
"ON UPDATE CASCADE " & _
"ON DELETE CASCADE"
注意 DDL 语句改变了tblInvoices
表单并添加了牢固的外关键字限制。同时它也通过使用级联子句在tblInvoices
和 tblCustomers 之间建立了一个数据关联。
关闭VBA 开发环境。
关闭Intermediate DDL 语句窗体。
从Tools菜单中,选择Relationships…菜单项以打开关联窗口。
双击tblCustomers 和 tblInvoices 之间的关联链接以打开Edit
Relationships对话框。
注意级联性更新和删除选项没有被设置。
关闭对话框。
当关联链接仍然显示时,按Delete键删除联接。
关闭关联窗口。
如果Intermediate DDL
语句在数据库窗口仍然显示,点击数据库窗口工具条中的Open按键。
点击Alter Table w/ Fast Foreign
Key按键产生一个外关键字联系。
关闭Intermediate DDL 语句窗体。
当新的关系链接被创建后,使用前面提到的步骤打开Edit
Relationships对话框。
注意级联性更新和删除选项已经被设置。
中级 DML 语句
这个acIntSQL数据库有许多关于数据处理语言 (DML)
语句的例子,在这些范例里你可以用它们来找到数据,并且它们中的大多数是以查询的形式实现的。仅有的以在线SQL形式实现的DML
语句则是基于中级DML
语句窗体的。窗体中的三个例子在LIKE子句中使用"_" 和
"%" 通配符,并使用SELECT INTO
语句在一个外部数据库中创建一个表单。
在acIntSQL 数据库中保存的两个查询是属于DML
语句内容却执行类似DDL的操作。其中的SELECT INTO
语句从已有的数据库中找到数据并用这些数据创建新的工作表。通过这些范例的学习,你将学会如何删除目标工作表,前提是这些工作表已经存在。
在中级DML语句的窗体中的Create Customers
Database输出指令和按键展示了一个对SELECT INTO
语句的有趣应用。这是一个告诉你使用中级SQL
语句所能完成的各种事情的一个好的例子。下面就是关于输出命令和按键的子过程的代码:
Private Sub cmdCreateDB_Click()
Dim conCatalog As ADOX.Catalog
Dim conDatabase As ADODB.Connection
Dim SQL As String
Dim sDBName As String
On Error GoTo Error_Handler
'Initialize objects & variables.
Set conDatabase = Application.CurrentProject.Connection
Set conCatalog = New ADOX.Catalog
sDBName = "C:Customers.mdb"
'Create the Customers database.
conCatalog.Create "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & sDBName
'Run the DML statement to build the Customers table.
SQL = "SELECT * INTO tblCustomers IN '" & sDBName & _
"'" & "FROM tblCustomers"
conDatabase.Execute SQL
MsgBox "The new CUSTOMERS database has been created " & _
"as " & sDBName & ".", vbInformation
conDatabase.Close
Set conDatabase = Nothing
Set conCatalog = Nothing
Exit Sub
Error_Handler:
MsgBox Err.Description, vbInformation
End Sub
如果客户数据库已经存在,那么代码将返回一个信息告诉你这个数据库无法被创建。让我们逐步的运行这个代码来看看它都做了什么。
坚持你的C:驱动器确定Customers.mdb文件不存在,如果存在就删除它。
打开acIntSQL 数据库。
确定tblCustomers数据库已经被创建并且此数据库已经装载了数据。
在数据库窗口从Objects条中选择Forms。
在数据库窗口工具条中着重显示Intermediate DM
语句的窗体并单击Open按键。
单击Create Customers Database按键创建新的数据库。
切换到资源管理器查看你的C盘驱动器内容。Customers.mdb
数据库文件应该已经被创建。
双击Customers.mdb数据库文件以打开另一个Access实例。
打开tblCustomers 数据库。注意它所包含的数据和 acIntSQL
数据库里的tblCustomers 所包含的数据相同。
这个产生新的数据库的代码范例是通过Jet OLE DB
provider使用ADOX 对象库来创建Access数据库。对于ADOX
对象库的讨论已经超出了本文的范围。如果你想知道更多关于它的信息,在Access
2000 在线帮助中查找"Microsoft ActiveX Data Objects
(ADO)"并打开其目录直到你看见"Microsoft ADO Extensions for
DDL和 Security (ADOX) Programmer's Reference"。
结束语
我们向你展示了许多新的任务是如何完成,也告诉了你如何通过不同的方式完成相同得任务。那么你将选择什么途径和SQL技术就由你所做的应用程序的要求以及你自己对SQL语法的掌握水平所决定。