为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

[精品]用API禁止鼠标滚轮

2017-09-01 50页 doc 204KB 129阅读

用户头像

is_105949

暂无简介

举报
[精品]用API禁止鼠标滚轮[精品]用API禁止鼠标滚轮 用api禁止鼠标滚轮 如何在Access2000窗体中检测并禁止通过鼠标滚轮滚动到其他记录 大家都知道,在Access的默认情况下,你可以通过使用鼠标滚轮从一条记录滚动到另一条记录,但是Access本身似乎并没有提供对鼠标滚轮的完全控制和检测的方法(关于这点,你可以参考本站文章《如何禁用鼠标滚轮,》)。 这里,你可以通过两种方法来检测并控制鼠标滚轮: 一、用 VB VC 编写 ActiveX DLL,通过在Access中引用该DLL来解决;(MS 推荐) 二、你可以在 Access 本...
[精品]用API禁止鼠标滚轮
[精品]用API禁止鼠标滚轮 用api禁止鼠标滚轮 如何在Access2000窗体中检测并禁止通过鼠标滚轮滚动到其他记录 大家都知道,在Access的默认情况下,你可以通过使用鼠标滚轮从一条记录滚动到另一条记录,但是Access本身似乎并没有提供对鼠标滚轮的完全控制和检测的方法(关于这点,你可以参考本站文章《如何禁用鼠标滚轮,》)。 这里,你可以通过两种方法来检测并控制鼠标滚轮: 一、用 VB VC 编写 ActiveX DLL,通过在Access中引用该DLL来解决;(MS 推荐) 二、你可以在 Access 本身的 VBA 代码中引用 API 函数建立子类来解决问题。 方法一: 以下就是方法一的操作过程: 1、打开 Microsoft Visual Basic 6.0. 2、建立一个新的 ActiveX DLL 项目并打开 3、将以下代码加入一个类模块中: Option Compare Text Option Explicit Private frm As Object Private intCancel As Integer Public Event MouseWheel(Cancel As Integer) Public Property Set Form(frmIn As Object) Set frm = frmIn End Property Public Property Get MouseWheelCancel() As Integer MouseWheelCancel = intCancel End Property Public Sub SubClassHookForm() lpPrevWndProc = SetWindowLong(frm.hwnd, GWL_WNDPROC, _ AddressOf WindowProc) Set Cmouse = Me End Sub Public Sub SubClassUnHookForm() Call SetWindowLong(frm.hwnd, GWL_WNDPROC, lpPrevWndProc) End Sub Public Sub FireMouseWheel() RaiseEvent MouseWheel(intCancel) End Sub 4、命名为: CMouseWheel 5、修改以下属性: Name: CMouseWheel Instancing: 5 - MultiUse 6、新建一个标准模块,然后加入以下代码: Option Compare Text Option Explicit Public Cmouse As CMouseWheel Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _ (ByVal hwnd As Long, _ ByVal nIndex As Long, _ ByVal dwNewLong As Long) As Long Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" _ (ByVal lpPrevWndFunc As Long, _ ByVal hwnd As Long, _ ByVal msg As Long, _ ByVal wParam As Long, _ ByVal lParam As Long) As Long Public Const GWL_WNDPROC = -4 Public Const WM_MouseWheel = &H20A Public lpPrevWndProc As Long Public Function WindowProc(ByVal hwnd As Long, _ ByVal uMsg As Long, _ ByVal wParam As Long, _ ByVal lParam As Long) As Long Select Case uMsg Case WM_MouseWheel Cmouse.FireMouseWheel If Cmouse.MouseWheelCancel = False Then WindowProc = CallWindowProc(lpPrevWndProc, hwnd, uMsg, wParam, lParam) End If Case Else WindowProc = CallWindowProc(lpPrevWndProc, hwnd, uMsg, wParam, lParam) End Select End Function 7、更改项目名称为:MouseWheel 8、保存该项目、类模块、标准模块 basSubClassWindow.bas CMouseWheel.cls MouseWheel.vbp respectively. 9、用“文件”菜单上的 建立 MouseWheel.dll 生成一个dll文件。 10、退出 VB 并打开 Access,打开示例数据库 Northwind.mdb 11、转到 VBE 界面,打开 form_Customers 类模块 12、工具菜单 -> 引用 ,然后找到你刚才生成的 MouseWheel.DLL 并选勾。 13、加入以下代码到该模块: Option Compare Database Option Explicit Private WithEvents clsMouseWheel As MouseWheel.CMouseWheel Private Sub Form_Load() Set clsMouseWheel = New MouseWheel.CMouseWheel Set clsMouseWheel.Form = Me clsMouseWheel.SubClassHookForm End Sub Private Sub Form_Close() clsMouseWheel.SubClassUnHookForm Set clsMouseWheel.Form = Nothing Set clsMouseWheel = Nothing End Sub Private Sub clsMouseWheel_MouseWheel(Cancel As Integer) MsgBox "You cannot use the mouse wheel to scroll records." Cancel = True End Sub 14、关闭,保存,打开窗体 Customers,然后滚动鼠标滚轮,你就会得到以下提示: You cannot use the mouse wheel to scroll records. 并且在提示的同时,当前记录并没有改动。 注意,如果你的 Access 程序的使用者已经加载了 VBE ,使用上述方法可能导致 Access 长时间停顿,你将不得不强行终止 Access 程序。所以,在进行上述操作时请注意备份数据库。 方法二: 方法二的操作过程: 下面示例如何在 Access 中直接写类模块来检测并禁止鼠标滚轮。(再说一遍:请先备份) 1、打开 Access ,并打开示例数据库 Northwind.mdb. 2、在 VBE 界面建立一个新的模块,并加入以下代码: Option Compare Database Option Explicit Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _ (ByVal hwnd As Long, _ ByVal nIndex As Long, _ ByVal dwNewLong As Long) As Long Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" _ (ByVal lpPrevWndFunc As Long, _ ByVal hwnd As Long, _ ByVal msg As Long, _ ByVal wParam As Long, _ ByVal lParam As Long) As Long Public Const GWL_WNDPROC = -4 Public Const WM_MouseWheel = &H20A Public lpPrevWndProc As Long Public Cmouse As CMouseWheel Public Function WindowProc(ByVal hwnd As Long, _ ByVal uMsg As Long, _ ByVal wParam As Long, _ ByVal lParam As Long) As Long 'Look at the message passed to the window. If it is 'a mouse wheel message, call the FireMouseWheel procedure 'in the CMouseWheel class, which in turn raises the MouseWheel 'event. If the Cancel argument in the form event procedure is 'set to False, then we process the message normally, otherwise 'we ignore it. If the message is something other than the mouse 'wheel, then process it normally Select Case uMsg Case WM_MouseWheel Cmouse.FireMouseWheel If Cmouse.MouseWheelCancel = False Then WindowProc = CallWindowProc(lpPrevWndProc, hwnd, uMsg, wParam, lParam) End If Case Else WindowProc = CallWindowProc(lpPrevWndProc, hwnd, uMsg, wParam, lParam) End Select End Function 3、保存类,名为:basSubClassWindow 4、建立一个类模块,并且加入以下代码: Option Compare Database Option Explicit Private frm As Access.Form Private intCancel As Integer Public Event MouseWheel(Cancel As Integer) Public Property Set Form(frmIn As Access.Form) 'Define Property procedure for the class which 'allows us to set the Form object we are 'using with it. This property is set from the 'form class module. Set frm = frmIn End Property Public Property Get MouseWheelCancel() As Integer 'Define Property procedure for the class which 'allows us to retrieve whether or not the Form 'event procedure canceled the MouseWheel event. 'This property is retrieved by the WindowProc 'function in the standard basSubClassWindow 'module. MouseWheelCancel = intCancel End Property Public Sub SubClassHookForm() 'Called from the form's OnOpen or OnLoad 'event. This procedure is what "hooks" or 'subclasses the form window. If you hook the 'the form window, you must unhook it when completed 'or Access will crash. lpPrevWndProc = SetWindowLong(frm.hwnd, GWL_WNDPROC, _ AddressOf WindowProc) Set Cmouse = Me End Sub Public Sub SubClassUnHookForm() 'Called from the form's OnClose event. 'This procedure must be called to unhook the 'form window if the SubClassHookForm procedure 'has previously been called. Otherwise, Access will 'crash. Call SetWindowLong(frm.hwnd, GWL_WNDPROC, lpPrevWndProc) End Sub Public Sub FireMouseWheel() 'Called from the WindowProc function in the 'basSubClassWindow module. Used to raise the 'MouseWheel event when the WindowProc function 'intercepts a mouse wheel message. RaiseEvent MouseWheel(intCancel) End Sub 5、保存类模块,名字为:CMouseWheel 6、打开 form_Customers 类,加入以下代码: Option Compare Database Option Explicit 'Declare a module level variable as the custom class 'and give us access to the class's events Private WithEvents clsMouseWheel As CMouseWheel Private Sub Form_Load() 'Create a new instance of the class, 'and set the class's Form property to 'the current form Set clsMouseWheel = New CMouseWheel Set clsMouseWheel.Form = Me 'Subclass the current form by calling 'the SubClassHookForm method in the class clsMouseWheel.SubClassHookForm End Sub Private Sub Form_Close() 'Unhook the form by calling the 'SubClassUnhook form method in the 'class, and then destroy the object 'variable clsMouseWheel.SubClassUnHookForm Set clsMouseWheel.Form = Nothing Set clsMouseWheel = Nothing End Sub Private Sub clsMouseWheel_MouseWheel(Cancel As Integer) 'This is the event procedure where you can 'decide what to do when the user rolls the mouse. 'If setting Cancel = True, we disable the mouse wheel 'in this form. MsgBox "You cannot use the mouse wheel to scroll through records." Cancel = True End Sub 7、保存,并关闭。 注意: 不要立即打开窗体验证代码是否正确,否则你的access将陷入长时间的停顿,因为 VBE 已经被加载了。 立即退出 Access ,然后重新打开数据库,滚动滚轮,你将看到以下提示: You cannot use the mouse wheel to scroll through records. 并且记录没有更改。 ,,, 语法参考手册 DB2 提供了关连式资料库的查询语言 ,,, (Structured Query Language), 是一种非常口语化、既易学又易懂的语法。此一语言几乎是每个资料库系统都 必须提供的,用以示关连式的操作,包含了资料的定义(,,,)以及资料 的处理(,,,)。SQL原来拼成 SEQUEL,这语言的原型以“系统 R“的名 字在 IBM 圣荷西实验室完成,经过 IBM 内部及其他的许多使用性及效率测试, 其结果相当令人满意,并决定在系统R 的技术基础发展出来 IBM 的产品。而 且美国国家标准学会(ANSI)及国际标准化组织(ISO 在 1987 遵循一个几乎 是以 IBM SQL 为基础的标准关连式资料语言定义。 基本查询 SELECT column1,columns2,... FROM table_name 说明:把table_name 的特定栏位资料全部列出来 SELECT * FROM table_name WHERE column1 = xxx [AND column2 > yyy] [OR column3 <> zzz] 说明: 1.'*'表示全部的栏位都列出来 2.WHERE 之後是接条件式,把符合条件的资料列出来 SELECT column1,column2 FROM table_name ORDER BY column2 [DESC] 说明: ORDER BY 是指定以某个栏位做排序,[DESC]是指从大到小排列,若 没有指明,则是从小到大排列 组合查询 组合查询是指所查询得资料来源并不只有单一的表格,而是联合一个以上的表格才能够得到 结果的。 SELECT * FROM table1,table2 WHERE table1.colum1=table2.column1 说明: 1.查询两个表格中其中 column1 值相同的资料 2.当然两个表格相互比较的栏位,其资料形态必须相同 3.一个复杂的查询其动用到的表格可能会很多个 整合性的查询: SELECT COUNT (*) FROM table_name WHERE column_name = xxx 说明: 查询符合条件的资料共有几笔 SELECT SUM(column1) FROM table_name 说明: 1.计算出总和,所选的栏位必须是可数的数字形态 2.除此以外还有 AVG() 是计算平均、MAX()、MIN() 计算最大最小值的整合性查询 SELECT column1,AVG(column2) FROM table_name GROUP BY column1 HAVING AVG(column2) > xxx 说明: 1.GROUP BY: 以column1 为一组计算 column2 的平均值 必须和 AVG、SUM 等整合性查询的关键字一起使用 2.HAVING : 必须和 GROUP BY 一起使用作为整合性的限制 复合性的查询 SELECT * FROM table_name1 WHERE EXISTS ( SELECT * FROM table_name2 WHERE conditions ) 说明: 1.WHERE 的 conditions 可以是另外一个的 query 2.EXISTS 在此是指存在与否 SELECT * FROM table_name1 WHERE column1 IN ( SELECT column1 FROM table_name2 WHERE conditions ) 说明 1. IN 後面接的是一个集合,表示column1 存在集合里面 2. SELECT 出来的资料形态必须符合 column1 其他查询 SELECT * FROM table_name1 WHERE column1 LIKE 'x%' 说明: LIKE 必须和後面的'x%' 相呼应表示以 x为开头的字串 SELECT * FROM table_name1 WHERE column1 IN ('xxx','yyy',..) 说明 IN 後面接的是一个集合,表示column1 存在集合里面 SELECT * FROM table_name1 WHERE column1 BETWEEN xx AND yy 说明 BETWEEN 表示 column1 的值介於 xx 和 yy 之间 更改资料: UPDATE table_name SET column1='xxx' WHERE conditoins 说明: 1.更改某个栏位设定其值为'xxx' 2.conditions 是所要符合的条件、若没有 WHERE 则 整个 table 的那个栏位都会全部被更改 删除资料: DELETE FROM table_name WHERE conditions 说明:删除符合条件的资料 MS Jet SQL for Access 2000中级篇 中级数据操纵语言 《基础Microsoft Jet SQL for Access 2000》一文告诉我们如何使用SQL来检索和管理存储在数据库中的信息。本文的后面部分将讨论中级数据操纵语言(DML)语句,这将使得用户可以更好的控制信息检索和处理的方式。 谓词 谓词指限定一个SELECT 语句的子句,同WHERE 子句类似,但是谓词是在书写列的列表之前定义的。谓词还可以进一步的限制用户所提取的记录集,在某些情况下,过滤出任何可能存在的重复值。 ALL关键字 在SQL语句中,如果没有定义任何谓词的话,将使用缺省的ALL关键字。它意味着所有的符合SQL语句所设定的条件的记录都将被提取出来。回到我们的发票数据库中,从顾客表中提取所域的记录如下: SELECT * FROM tblCustomers 注意尽管这里ALL关键词并没有定义,但它是缺省值。我们也可以如下书写该语句: SELECT ALL * FROM tblCustomers DISTINCT关键字 DISTINCT关键字用来控制结果集中重复的值如何进行处理,那些对于指定的列来说用户相同值的行将被过滤掉。如果多于指定的列大于一,则所有指定的列的结合将作为过滤条件。例如,如果用户查询Customers表中姓氏不同的记录,则返回的值都将是唯一的,任何重复姓氏的名字都将以结果集中的一个记录作为其结果。 SELECT DISTINCT [Last Name] FROM tblCustomers 尤其要注意的是,使用DISTINCT关键字的查询所返回的结果集不能更新,即是只读的。 DISTINCTROW 关键字 DISTINCTROW 关键字和DISTINCT关键字类似,但前者是基于整行而非个别的域的。他只有在处理多个表时,并且只有在用户从某几个但非全部的表中选择数据域时才是有用的。如果用户的查询是基于一个表的,或者要从所有的表中选择数据域,则DISTINCTROW 关键字本质上和ALL关键字相同。 例如,在我们的发票数据库中,每个顾客都可能没有、有一个或多个发票记录。假设我们希望找出有多少拥有多于一张发票的顾客,这时可以使用DISTINCTROW关键字来进行选择。 SELECT DISTINCTROW [Last Name], [First Name] FROM tblCustomers INNER JOIN tblInvoices ON tblCustomers.CustomerID = tblInvoices.CustomerID 如果我们不使用DISTINCTROW 关键字,得到的将是每个顾客的所有发票记录的行。(这里的 INNER JOIN 语句将在后面的部分讲解)。 TOP关键字 TOP关键字用来返回通过ORDER BY子句所指定的数据行中顶部或底部的某些行。ORDER BY 子句用来指定这些数据列是用升序还是降序排列。如果存在相等值,则TOP关键字将返回所有值相等的行。比如我们希望确定我们的发票数据库中最高额的三条发票记录,可以如下书写SQL语句: SELECT TOP 3 InvoiceDate, Amount FROM tblInvoices ORDER BY Amount DESC 我们也可以将PERCENT关键字和TOP关键字同时使用,来返回由ORDER BY子句所指定的数据行中顶部或底部的一定比例的行,如下所示: SELECT TOP 25 PERCENT InvoiceDate, Amount FROM tblInvoices ORDER BY Amount DESC 注意如果用户没有定义ORDER BY 子句,则TOP关键字将毫无意义,返回的是随机采样的一些行。 要了解有关谓词的更多信息,请在Office 助手中或在Microsoft Access 帮助的回答向导的标签页中输入ALL、DISTINCT等谓词,然后单击查找。 SQL 表达式 一个SQL表达式就是作为SQL语句的一部分的一个字符串,并可以得到一个值。你可以任 意组合运算符、常数、文字值、函数、域名、控制和属性来建立你的SQL表达式。而" Microsoft Jet SQL for Access 2000高级版"一文就向你描述了如何在WHERE子句中使用表达式来限制SQL语句;而且在本文随后的部分,我们将学习各种能够用于表达式的SQL操作符。 IN操作 IN操作是用来判断一个表达式的值是否属于一个指定列表中的值。如果这个表达式等于列表中的一个值,IN操作的返回值为True。而当没有找到,IN操作返回值为False。让我们假设我们想找到所有住在华盛顿州或乔治亚州的销售部成员。我们可以写一个带着长长的WHERE 子句,并使用AND逻辑操作符的SQL语句,而使用IN操作符会缩短我们写的语句。 SELECT * FROM tblShipping WHERE State IN ('WA','GA') 通过使用NOT逻辑操作符,我们可以检索出IN操作的反操作结果,这个语句会返回所有不住在华盛顿州的销售部成员。 SELECT * FROM tblShipping WHERE State NOT IN ('WA') BETWEEN操作 BETWEEN操作用于判断一个表达式的值是否介于一个特定的范围之间。如果这个表达式的值介于这个特定范围之间,包括范围开始和结束的值,这个BETWEEN操作返回True。如果这个表达式得值不属于这个范围,则BETWEEN操作返回值为False。假设我们想找到所以金额介于50美圆到100美圆之间的所有发票。我们最好在WHERE 子句使用BETWEEN 操作以及关键字AND设定范围。 SELECT * FROM tblInvoices WHERE Amount BETWEEN 50 and 100 通过使用NOT逻辑操作符,我们可以检索出BETWEEN操作的反操作结果,找到不在范围中的所有发票数量。 SELECT * FROM tblInvoices WHERE Amount NOT BETWEEN 50 and 100 注意这个范围可以设定为相反的顺序并依旧得到相同的结果 (BETWEEN 100 和 50),但许多的适用于ODBC的数据库要求这个范围遵从从头到尾的顺序。如果你设计你的应用程序可以兼容或升级为适用于ODBC的数据库,你就应该总是按照从头到尾的方法使用。 LIKE操作 LIKE 操作operator is used to determine if the value of an expression compares to that of a pattern. 一个样式就是就是一个完全的字符串或是一个包含有一个或多个通配符的部分字符串。通过使用LIKE 操作,你可以在一个结果集里查找一个域并找到所有符合特殊的样式的值。 SELECT * FROM tblCustomers WHERE [Last Name] LIKE 'Johnson' 为了返回所有的名字以字母J开头的顾客,我们使用星号通配符。 SELECT * FROM tblCustomers WHERE [Last Name] LIKE 'J*' 通过使用NOT逻辑操作符,我们可以检索出LIKE操作的反操作,并在列表中过滤掉所有的 Johnsons。 SELECT * FROM tblCustomers WHERE [Last Name] NOT LIKE 'Johnson' 你在LIKE 操作样式里可以使用多种通配符,如下表所示: 通配符 描述 *(星号) 匹配所有字符并可以被用在结构字符串的任何位置。 %(百分号) 批评任何字符并可以被用在结构字符串的任何位置。(只适用于ADO 和 the Jet OLE DB provider) ?(问号) 匹配任何单个字符并可以被用在结构字符串的任何位置。 _(下划线) 匹配任何单个字符并可以被用在结构字符串的任何位置。(只适用于ADO 和 the Jet OLE DB provider) #(数字符号) 匹配任何单个数字并可以被用在结构字符串的任何位置。 [](方括号) 匹配任何被包括在方括号里面的单个字符,并可以被用在结构字符串的任何位置。 !(感叹号) 匹配任何不属于被方括号所包含的字符列表中的单个字符。Matches any single character not in the list that is enclosed within the square brackets. -(连字符) 匹配任何一个在方括号中的字符。 注意: 上表所述的“%”和“_”通配符只能通过Jet OLE DB provider 或 ADO运行。如果通过. Access SQL View 用户界面运行它们将获得一个空的结果集。 如果你想得到更多的通配符的信息,在Office 助理或微软Access帮助窗体的Answer Wizard标志中输入wildcard characters,并单击Search。 IS NULL 操作符 空值就是指无值或不可知值。IS NULL操作符被用于判断一个表达式的值是否和一个空值相等。 SELECT * FROM tblInvoices WHERE Amount IS NULL 通过添加NOT逻辑操作符,我们可以检索IS NULL操作符的反操作。在这个例子里,SQL语句将会除掉所有包含丢失的或未知值的发票记录。 SELECT * FROM tblInvoices WHERE Amount IS NOT NULL SELECT INTO 语句 SELECT INTO 语句,也可以理解为一个表单创建查询,可以用来从一个或多个已存在工作表中创建一个新的工作表。它所创建的工作表可以基于任何有效的SELECT语句。SELECT INTO 语句可以用来存储记录、创建备份表单或在一个外部数据库里创建新的工作表。 当你用SELECT INTO 语句创建一个新工作表时,所有的新工作表里的域都继承于原始工作表。然而,不包括其他的工作表属性,如主关键字或索引都是在新工作表中被创建。一旦新的工作表被创建,你当然可以使用ALTER TABLE语句添加这些属性。 如果你要创建一个新的工作表,可以使用一个带有你希望在工作表种包含的列的域列表和你新工作表的名称的SELECT INTO 语句,并在FROM子句里提供数据资源。 SELECT * INTO tblNewCustomers FROM tblCustomers 为了为新的工作表指定确定的域,把域名列表里的原始工作表的域名用星号代替,并用AS关键字来命名新的工作表中的各列。 SELECT [First Name] & ' ' & [Last Name] AS FullName INTO tblNewCustomerNames FROM tblCustomers 如果要在一个已经存在的外部数据库里创建新的工作表,你可以用IN关键字。如果外部数据库不存在,SELECT INTO 语句将会返回一个错误信息。 SELECT * INTO tblNewCustomers IN 'C:\Customers.mdb' FROM tblCustomers 子查询 子查询就是在用在另一个SELECT、SELECT INTO、INSETT INTO 、DELETE 或UPDATE语句内部的SELECT语句。它可以帮助你对基于另一个结果集的结果进行进一步的限制。这叫做嵌入,并且因为一个子查询就是一个SELECT语句,你也可以把一个子查询嵌入到另一个子查询里面。当你在一个SQL语句中使用一个子查询的时候,它可以作为一个域列表、WHERE子句或者HAVING子句的一部分。 这里由三种基本的子查询形式,并且每种都使用不同种类的谓词。 IN子查询 IN 子查询用于检索这样的一组值,即其中记录的某一列的值都为另一个工作表或查询中的一列的值包含。它从其它工作表中只能返回一列,这是一个限制条件。如果返回的多于一列就会产生一个错误。使用发票数据库例子,我们可以写出一个返回所有拥有发票的顾客的列表的,,,语句。 SELECT * FROM tblCustomers WHERE CustomerID IN (SELECT CustomerID FROM tblInvoices) 通过使用NOT逻辑操作符,我们可以检索和,,子查询相反的记录,从而可以获得所有没有任何发票的顾客列表。 SELECT * FROM tblCustomers WHERE CustomerID NOT IN (SELECT CustomerID FROM tblInvoices) ANY/SOME/ALL子查询 ANY、 SOME和ALL子查询谓词被用于比较主查询的记录和子查询的多个输出记录。ANY 和 SOME谓词是同义词并可以被替换使用。 当你需要从主查询中检索任何符合在子查询中满足比较条件的记录时可以使用ANY或 SOME谓词。谓词应该恰好放在子查询开始的括号前面。 SELECT * FROM tblCustomers WHERE CustomerID = ANY (SELECT CustomerID FROM tblInvoices) 注意由上面SQL语句所返回的结果集和IN子查询例子所返回的那个相同。而与ANY和SOME谓词的不同之处就在于它们都可以使用等于(=)以外的操作符,比如大于(>)和小于(<)。 SELECT * FROM tblCustomers WHERE CustomerID > 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语法的掌握水平所决定。 SQL--JOIN之完全用法 外联接。外联接可以是左向外联接、右向外联接或完整外部联接。 在 FROM 子句中指定外联接时,可以由下列几组关键字中的一组指定: LEFT JOIN 或 LEFT OUTER JOIN。 左向外联接的结果集包括 LEFT OUTER 子句中指定的左表的所有行,而不仅仅是联接列所匹配的行。如果左表的某行在右表中没有匹配行,则在相关联的结果集行中右表的所有选择列表列均为空值。 RIGHT JOIN 或 RIGHT OUTER JOIN。 右向外联接是左向外联接的反向联接。将返回右表的所有行。如果右表的某行在左表中没有匹配行,则将为左表返回空值。 FULL JOIN 或 FULL OUTER JOIN。 完整外部联接返回左表和右表中的所有行。当某行在另一个表中没有匹配行时,则另一个表的选择列表列包含空值。如果表之间有匹配行,则整个结果集行包含基表的数据值。 仅当至少有一个同属于两表的行符合联接条件时,内联接才返回行。内联接消除与另一个表中的任何行不匹配的行。而外联接会返回 FROM 子句中提到的至少一个表或视图的所有行,只要这些行符合任何 WHERE 或 HAVING 搜索条件。将检索通过左向外联接引用的左表的所有行,以及通过右向外联接引用的右表的所有行。完整外部联接中两个表的所有行都将返回。 Microsoft? SQL Server? 2000 对在 FROM 子句中指定的外联接使用以下 SQL-92 关键字: LEFT OUTER JOIN 或 LEFT JOIN RIGHT OUTER JOIN 或 RIGHT JOIN FULL OUTER JOIN 或 FULL JOIN SQL Server 支持 SQL-92 外联接语法,以及在 WHERE 子句中使用 *= 和 =* 运算符指定外联接的旧式语法。由于 SQL-92 语法不容易产生歧义,而旧式 Transact-SQL 外联接有时会产生歧义,因此建议使用 SQL-92 语法。 使用左向外联接 假设在 city 列上联接 authors 表和 publishers 表。结果只显示在出版商所在城市居住的作者(本例中为 Abraham Bennet 和 Cheryl Carson)。 若要在结果中包括所有的作者,而不管出版商是否住在同一个城市,请使用 SQL-92 左向外联接。下面是 Transact-SQL 左向外联接的查询和结果: USE pubs SELECT a.au_fname, a.au_lname, p.pub_name FROM authors a LEFT OUTER JOIN publishers p ON a.city = p.city ORDER BY p.pub_name ASC, a.au_lname ASC, a.au_fname ASC 下面是结果集: au_fname au_lname pub_name ------------------- ------------------------------ ----------------- Reginald Blotchet-Halls NULL Michel DeFrance NULL Innes del Castillo NULL Ann Dull NULL Marjorie Green NULL Morningstar Greene NULL Burt Gringlesby NULL Sheryl Hunter NULL Livia Karsen NULL Charlene Locksley NULL Stearns MacFeather NULL Heather McBadden NULL Michael O'Leary NULL Sylvia Panteley NULL Albert Ringer NULL Anne Ringer NULL Meander Smith NULL Dean Straight NULL Dirk Stringer NULL Johnson White NULL Akiko Yokomoto NULL Abraham Bennet Algodata Infosystems Cheryl Carson Algodata Infosystems (23 row(s) affected) 不管是否与 publishers 表中的 city 列匹配,LEFT OUTER JOIN 均会在结果中包含 authors 表的所有行。注意:结果中所列的大多数作者都没有相匹配的数据,因此,这些行的 pub_name 列包含空值。 使用右向外联接 假设在 city 列上联接 authors 表和 publishers 表。结果只显示在出版商所在城市居住的作者(本例中为 Abraham Bennet 和 Cheryl Carson)。SQL-92 右向外联接运算符 RIGHT OUTER JOIN 指明:不管第一个表中是否有匹配的数据,结果将包含第二个表中的所有行。 若要在结果中包括所有的出版商,而不管城市中是否还有出版商居住,请使用 SQL-92 右向外联接。下面是 Transact-SQL 右向外联接的查询和结果: USE pubs SELECT a.au_fname, a.au_lname, p.pub_name FROM authors AS a RIGHT OUTER JOIN publishers AS p ON a.city = p.city ORDER BY p.pub_name ASC, a.au_lname ASC, a.au_fname ASC 下面是结果集: au_fname au_lname pub_name -------------------- ------------------------ -------------------- Abraham Bennet Algodata Infosystems Cheryl Carson Algodata Infosystems NULL NULL Binnet & Hardley NULL NULL Five Lakes Publishing NULL NULL GGG&G NULL NULL Lucerne Publishing NULL NULL New Moon Books NULL NULL Ramona Publishers NULL NULL Scootney Books (9 row(s) affected) 使用谓词(如将联接与常量比较)可以进一步限制外联接。下例包含相同的右向外联接,但 消除销售量低于 50 本的书籍的书名: USE pubs SELECT s.stor_id, s.qty, t.title FROM sales s RIGHT OUTER JOIN titles t ON s.title_id = t.title_id AND s.qty > 50 ORDER BY s.stor_id ASC 下面是结果集: stor_id qty title ------- ------ --------------------------------------------------------- (null) (null) But Is It User Friendly? (null) (null) Computer Phobic AND Non-Phobic Individuals: Behavior Variations (null) (null) Cooking with Computers: Surreptitious Balance Sheets (null) (null) Emotional Security: A New Algorithm (null) (null) Fifty Years in Buckingham Palace Kitchens 7066 75 Is Anger the Enemy? (null) (null) Life Without Fear (null) (null) Net Etiquette (null) (null) Onions, Leeks, and Garlic: Cooking Secrets of the Mediterranean (null) (null) Prolonged Data Deprivation: Four Case Studies (null) (null) Secrets of Silicon Valley (null) (null) Silicon Valley Gastronomic Treats (null) (null) Straight Talk About Computers (null) (null) Sushi, Anyone? (null) (null) The Busy Executive's Database Guide (null) (null) The Gourmet Microwave (null) (null) The Psychology of Computer Cooking (null) (null) You Can Combat Computer Stress! (18 row(s) affected) 有关谓词的更多信息,请参见 WHERE。 使用完整外部联接 若要通过在联接结果中包括不匹配的行保留不匹配信息,请使用完整外部联接。Microsoft? SQL Server? 2000 提供完整外部联接运算符 FULL OUTER JOIN,不管另一个表是否有匹 配的值,此运算符都包括两个表中的所有行。 假设在 city 列上联接 authors 表和 publishers 表。结果只显示在出版商所在城市居住的作 者(本例中为 Abraham Bennet 和 Cheryl Carson)。SQL-92 FULL OUTER JOIN 运算符指明: 不管表中是否有匹配的数据,结果将包括两个表中的所有行。 若要在结果中包括所有作者和出版商,而不管城市中是否有出版商或者出版商是否住在同一个城市,请使用完整外部联接。下面是 Transact-SQL 完整外部联接的查询和结果: USE pubs SELECT a.au_fname, a.au_lname, p.pub_name FROM authors a FULL OUTER JOIN publishers p ON a.city = p.city ORDER BY p.pub_name ASC, a.au_lname ASC, a.au_fname ASC 下面是结果集: au_fname au_lname pub_name -------------------- ---------------------------- -------------------- Reginald Blotchet-Halls NULL Michel DeFrance NULL Innes del Castillo NULL Ann Dull NULL Marjorie Green NULL Morningstar Greene NULL Burt Gringlesby NULL Sheryl Hunter NULL Livia Karsen NULL Charlene Locksley NULL Stearns MacFeather NULL Heather McBadden NULL Michael O'Leary NULL Sylvia Panteley NULL Albert Ringer NULL Anne Ringer NULL Meander Smith NULL Dean Straight NULL Dirk Stringer NULL Johnson White NULL Akiko Yokomoto NULL Abraham Bennet Algodata Infosystems Cheryl Carson Algodata Infosystems NULL NULL Binnet & Hardley NULL NULL Five Lakes Publishing NULL NULL GGG&G NULL NULL Lucerne Publishing NULL NULL New Moon Books NULL NULL Ramona Publishers NULL NULL Scootney Books (30 row(s) affected) Access不编程生成菜单,自定义菜单如何调用自定义过程 1.工具 -> 自定义 -> 工具栏 -> 新建 -> 将生成的工具栏"自定义1"选中 -> 属性 -> 将类型改为"菜单栏",其"工具栏名称"也可以改为其它名子,点击"关闭" 2.选择 "自定义" 框中的 命令->文件->自定义,将其拖至"自定义1"菜单栏(可反复拖取)->选取"自定义1"菜单栏中的某个菜单,单击右键,选"属性",可以更改菜单名"标题","所在操作"中填宏或function函数(其格式为“=FunctionName()”,注意,“=FunctionName()” 的两个括号不能少)。然后关闭对话框。 3.将所有的菜单都设置完后,再次选取"自定义"对话框中的"自定义1"菜单栏->选"属性"->将其"类型"改为"弹出式"。确定。 4.选取"自定义"->"工具栏"->"快捷菜单",勾取。可在出现的[快捷菜单]栏中看到"自定义"项,我们定义的快捷菜单就在内。可选取,单击右键,选"属性",更改其相应的属性。 5.在需要的地方,如下写码: CommandBars("自定义1").Controls(2).Enabled =True '定义其某个菜单是否可用。需要时再加。 CommandBars("自定义1").ShowPopup '弹出快捷菜单 如果"工具栏名称"为"右键菜单",则可写为: CommandBars("右键菜单").Controls(2).Enabled =True CommandBars("右键菜单").ShowPopup ACCESS查询,分段统计人数 这样一个表 tblScore: 班级 姓名 总分 语文 数学 1班 a 601 108 120 2班 b 589 112 133 3班 C 551 98 145 2班 D 502 80 124 1班 E 508 90 85 3班 F 561 97 135 TRANSFORM Count(tblScore.总分) AS 总分OfCount SELECT tblScore.班级 FROM tblScore GROUP BY tblScore.班级 PIVOT Switch([总分]>=600,">=600",[总分]>=550 And [总分]<600,"550-599",[总分]>=500 And [总分]<550,"500-549",True,"Other") In (">=600","550-599","500-549","Other"); 可得到第一個查詢 班级 总分600分以上人数 总分550-600人数 总分550以下人数 1班 1 0 1 2班 0 1 1 3班 0 2 0 数据库规格问题,如表能放多少字段 access 2000中文版为例 打开帮助,找到以下条目 设置和定义microsoft Access -> Microsoft Access 规格 自己去看吧 Microsoft Access 数据库常规规格 属性 最大值 Microsoft Access 数据库 (.mdb) 文件大小 2 G 字节。不过,由于数据库可以包括其他文件中的链接表,所以它的大小仅实际上只受可用存储空间大小的限制。 数据库中的对象个数 32,768 模块(包括 HasModule 属性为 True 的窗体和报表) 1,000 对象名称的字符数 64 密码的字符个数 14 用户名或组名的字符个数 20 用户个数 255 Microsoft Access 项目常规规格 属性 最大值 在 Microsoft Access 项目 (.adp) 中的对象数目 32,768 模块(包括 HasModule 属性为 True 的窗体和报表) 1,000 对象名称中字符的数目 64 Microsoft Access 数据库表规格 属性 最大值 表名的字符个数 64 字段名的字符个数 64 表中字段个数 255 打开表的个数 2,048。实际可打开的表的数目可能会少一些,因为 Microsoft Access 还要打开一些内部的表。 表的大小 1G 字节 文本字段的字符个数 255 备注字段的字符个数 通过用户界面输入为 65,535,通过程序输入为 1G 字节。 OLE 对象字段的大小 1G 字节 表中索引个数 32 索引中的字段个数 10 有效性消息的字符个数 255 有效性规则的字符个数 2,048 表或字段说明的字符个数 255 记录的字符个数(除了备注字段和 OLE 对象字段) 2,000 字段属性设置的字符个数 255 Microsoft Access 数据库查询规格 属性 最大值 实施关系的个数 每个表为 32 减去表中不包含在关系中的字段或字段组合的索引个数 查询中的表的个数 32 记录集中的字段个数 255 记录集大小 1G 字节 排序限制 255 个字符(一个或一个以上字段) 嵌套查询的级数 50 查询设计网格单元中的字符个数 1,024 参数查询的参数字符个数 255 WHERE 或 HAVING 子句中 AND 的个数 40 SQL 语句的字符个数 约为 64,000 窗体和报表规格 属性 最大值 标签中的字符个数 2,048 文本框中的字符个数 65,535 窗体或报表宽度 22 英寸(55.87 厘米) 节高度 22 英寸(55.87 厘米) 所有节加上节页眉的高度(在“设计”视图中) 200 英寸(508 厘米) 窗体或报表的最大嵌套级数 7 报表中可以排序或分组的字段或表达式个数 10 报表中页眉和页脚的个数 1 对报表页眉/报表页脚,1 对页面页眉/页面页脚,10 组页眉/ 组页脚 报表的打印页数 65,536 可添加到窗体或报表的控件和节的个数 754 宏规格 属性 最大值 宏中的操作个数 999 条件中的字符个数 255 注释的字符个数 255 操作参数的字符个数 255 Microsoft Access 项目规格Access 项目 属性 最大值 Microsoft Access 项目 (.adp)(Microsoft Access 项目:与 Microsoft SQL Server 数据库连接且用于创建客户/服务器应用程序的 Access 文件。项目文件中不包含任何数据或基于数据定义的对象(如表或视图)。) 中的对象数目 32,768 模块(包括“内含模块”属性为“是”的窗体和报表) 1,000 对象名称中的字符数 64 表中的索引个数 250 (Microsoft SQL Server 6.5) 1024(Microsoft SQL Server 7.0 和 2000) Microsoft SQL Server 数据库 SQL Server 文档中描述了 Microsoft SQL Server 最大容量规格。有关 SQL Server 联机丛书的详细信息,请参见 Microsoft Developer's Network Web 站点。 注意 使用该主题中的超链接会跳转到 Web 上,但随时可以切换回“帮助”。 窗体和报表 属性 最大值 标签中的字符个数 2,048 文本框中的字符个数 65,535 窗体或报表宽度 22 英寸(55.87 厘米) 节高度 22 英寸(55.87 厘米) 所有节加上节页眉的高度(在“设计”视图(“设计”视图:显示数据库对象(包括:表、查询、窗体、宏和数据访问页)的设计的窗口。在“设计”视图中,可以新建数据库对象和修改现有数据库对象的设计。)中) 200 英寸(508 厘米) 窗体或报表的最大嵌套层数 7 报表中可作为排序或分组依据的字段或表达式个数 10 报表中页眉和页脚的个数 1 对报表页眉/报表页脚,1 对页面页眉/页面页脚,10 对组页眉/组页脚 报表的打印页数 65,536 可添加到窗体或报表的控件和节的个数 754 SQL 语句中作为窗体、报表或控件的“记录源”或“行来源”属性的字符个数(适用于 .mdb 和 .adp) 32,750 宏 属性 最大值 宏(宏:用来自动执行任务的一个操作或一组操作。)中的操作个数 999 条件(条件:进行搜索或筛选时字段必须满足的准则部分。一些条件必须与值一起使用;例如,条件为“等于”的字段“作者”使用值“王良”。“作者”“等于”其自身将是不完整的。)中的字符个数 255 备注中的字符个数 255 操作参数(操作参数:有些宏操作所必需的其他信息,例如,受操作影响的对象或执行操作的特殊条件。)中的字符个数 255 ACCESS数据库中的中文报表制作 ---- MICROSOFT ACCESS是新一代关系型数据库管理系统,由于内置有功能强大的工具和方便有效的向导,ACCESS数据库系统提供了比其他数据库系统更方便的功能。在向导的帮助下,短短的几分钟内,我们就可以构造出一个数据库应用程序。 ---- 数据库应用中很关键的数据输出形式是“报表”,ACCESS提供的报表向导,只针对国外的报表形式,就是线条较少的报表。而我们的中文报表,传统形式是线条较多的网格形式,所以,不能简单地通过向导来完成。现就本人使用ACCESS的经验,结合实例,谈一下如何在ACCESS数据库中制作我们的中文报表。 ---- “产品销售利润明细表”的制作: ---- 1( 新建报表:选“自动报表:表格”,数据来源选表如XSLR表,确定后,产生一个简单的报表,在此基础上进行修改。 ---- 2( 页面设置:边距方面,调整靠左、靠右来达到最大打印范围。页面方面,打印方向设置为纵向,纸张大小选自定义大小,宽度为1660(最大),长度为1100(一页纸长度),单位为0.01英寸。 ---- 3( 版面设置:删除报表页眉、报表页脚。将页面页眉的内容删除。在页面页眉中插入对象,选MICROSOFT WORD文档,在WORD文档中画出表头,填上内容,注意,汉字之间要空一格,否则,到ACCESS报表输出时,汉字会出现乱码。对此OLE控件设置属性:背景样式为“透明”,边框样式为“透明”。在主体部件插入对象,选MICROSOFT WORD文档,在WORD文档中画出表格线方格,行宽可比表头行宽大一些,对此OLE控件设置属性:背景样式为“透明”,边框为实线,边框宽度为细线,设置各字段文字类型及大小,将各字段调整到方格内。 ---- 4( 在DETAIL的FORMAT事件中写入代码,以完成对零值的屏蔽。代码如下:(A3至A13为数值型字段) Private Sub Detail_Format (Cancel As Integer, FormatCount As Integer) If A3 = 0 Then A3.Visible = False Else A3.Visible = True End If If A4 = 0 Then A4.Visible = False Else A4.Visible = True End If If A7 = 0 Then A7.Visible = False Else A7.Visible = True End If If A8 = 0 Then A8.Visible = False Else A8.Visible = True End If If A9 = 0 Then A9.Visible = False Else A9.Visible = True End If If A11 = 0 Then A11.Visible = False Else A11.Visible = True End If If A12 = 0 Then A12.Visible = False Else A12.Visible = True End If If A13 = 0 Then A13.Visible = False Else A13.Visible = True End If End Sub Access数据有效性检查 开发一个好的数据库管理系统,关键是要确保录入数据的完整性和准确性。Access提供了 很多检查录入数据有效性的手段,笔者这里就简单介绍两种常用的方法。 一、利用字段属性 1.数据类型属性:数据类型决定了用户能保存在此字段中值的种类,如果用户键入的数据与字段规定的类型不一致,Access就不会存储该数据。如“日期/时间”字段,只允许输入有效的日期与时间格式。 2.字段大小属性:对于“数字”型字段,通过设置字段的大小控制输入值的类型和范围;而对“文本”字段,可以设置可输入的最大字符数(最大为255)。 3.必填字段属性:数据库中除“自动编号”字段外(该字段可自行生成数据)的其它字段,都可利用设置必填字段属性值为“是”,要求字段中必须有数据输入,以避免一些重要信息的遗漏。 4.输入掩码属性:该属性可帮助用户按照正确的格式输入数据。如创建输入掩码显示电话号码的括号、空格及连接符,输入时只要在空格中填入即可。 5.有效性规则属性:字段有效性规则属性用于在用户离开字段时,检查输入字段的值是否符合要求。 表有效性规则与字段有效性规则不同,当需要设置涉及表中多个字段的有效性规则属性时,可以设置表属性的有效性规则。 二、使用事件过程 在某些情况下,当有效性规则含有复杂的条件,并且需根据条件执行不同的操作时,往往很难写出有效性规则,这时可以通过对如下的事件过程编写代码来代替有效性规则进行检查。 BeforeUpdate和Ondelete窗体事件是在保存记录中的新数据或修改后的数据之前和在删除记录之前触发;BeforeUpdate和onExit控件事件是在保存控件上的新数据或修改后的数据之前和离开控件之前触发。 ACCESS中使用SQL语句应注意的地方及几点技巧 以下SQL语句在ACCESS XP的查询中测试通过 建表: Create Table Tab1 ( ID Counter, Name string, Age integer, [Date] DateTime); 技巧: 自增字段用 Counter 声明. 字段名为关键字的字段用方括号[]括起来,数字作为字段名也可行. 建立索引: 下面的语句在Tab1的Date列上建立可重复索引 Create Index iDate ON Tab1 ([Date]); 完成后ACCESS中字段Date索引属性显示为 - 有(有重复). 下面的语句在Tab1的Name列上建立不可重复索引 Create Unique Index iName ON Tab1 (Name); 完成后ACCESS中字段Name索引属性显示为 - 有(无重复). 下面的语句删除刚才建立的两个索引 Drop Index iDate ON Tab1; Drop Index iName ON Tab1; ACCESS与SQLSERVER中的UPDATE语句对比: SQLSERVER中更新多表的UPDATE语句: UPDATE Tab1 SET a.Name = b.Name FROM Tab1 a,Tab2 b WHERE a.ID = b.ID; 同样功能的SQL语句在ACCESS中应该是 UPDATE Tab1 a,Tab2 b SET a.Name = b.Name WHERE a.ID = b.ID; 即:ACCESS中的UPDATE语句没有FROM子句,所有引用的表都列在UPDATE关键字 后. 上例中如果Tab2可以不是一个表,而是一个查询,例: UPDATE Tab1 a,(Select ID,Name From Tab2) b SET a.Name = b.Name WHERE a.ID = b.ID; 访问多个不同的ACCESS数据库-在SQL中使用In子句: Select a.*,b.* From Tab1 a,Tab2 b In 'db2.mdb' Where a.ID=b.ID; 上面的SQL语句查询出当前数据库中Tab1和db2.mdb(当前文件夹中)中Tab2以ID为 关联的所有记录. 缺点-外部数据库不能带密码. 在ACCESS中访问其它ODBC数据源 下例在ACCESS中查询SQLSERVER中的数据 SELECT * FROM Tab1 IN [ODBC] [ODBC;Driver=SQL Server;UID=sa;PWD=;Server=127.0.0.1;DataBase=Demo;] 外部数据源连接属性的完整参数是: [ODBC;DRIVER=driver;SERVER=server;DATABASE=database;UID=user;PWD=password;] 其中的DRIVER=driver可以在注册表中的 HKEY_LOCAL_MACHINE\SOFTWARE\ODBC\ODBCINST.INI\ 中找到 ACCESS支持子查询 ACCESS支持外连接,但不包括完整外部联接,如支持 LEFT JOIN 或 RIGHT JOIN 但不支持 FULL OUTER JOIN 或 FULL JOIN ACCESS中的日期查询 注意:ACCESS中的日期时间分隔符是#而不是引号 Select * From Tab1 Where [Date]>#2002-1-1#; 在DELPHI中我这样用 SQL.Add(Format( 'Select * From Tab1 Where [Date]>#%s#;', [DateToStr(Date)])); ACCESS中的字符串可以用双引号分隔,但SQLSERVER不认,所以为了迁移方便和兼容, 建议用单引号作为字符串分隔符. ADP窗体打印当前记录 ADP窗体打印当前记录,用MDB的方法是不行的,不信你试试。必须使用存储过程。 例:有一个dbo.gytable的表,通过窗体连接进行操作,单击窗体的打印按钮,要能打 印窗体的当前记录。ADP窗体,用MDB的方法是不行的。 方法如下: 存储过程: Alter PROCEDURE dbo.dayin (过程名为dbo.dayin ) @txc char(30) (建一个txc的字符型变量,长度30) AS select * from dbo.gytable where(图号=@txc) (这个不要说了,大家都懂) 将报表的记录源设为dbo.gytable,就行了。 通过按钮的单击事件打开报表。 16. ASP与Access数据库连接: <%@ language=VBs cript%> <% dim conn,mdbfile mdbfile=server.mappath("数据库名称.mdb") set conn=server.createobject("adodb.connection") conn.open "driver={microsoft access driver (*.mdb)};uid=admin;pwd=数据库密 码;dbq="&mdbfile %> 18. SQL常用命令使用方法: (1) 数据记录筛选: sql="select * from 数据表 where 字段名=字段值 order by 字段名 [desc]" sql="select * from 数据表 where 字段名 like '%字段值%' order by 字段名 [desc]" sql="select top 10 * from 数据表 where 字段名 order by 字段名 [desc]" sql="select * from 数据表 where 字段名 in ('值1','值2','值3')" sql="select * from 数据表 where 字段名 between 值1 and 值2" (2) 更新数据记录: sql="update 数据表 set 字段名=字段值 where 条件表达式" sql="update 数据表 set 字段1=值1,字段2=值2 „„ 字段n=值n where 条件表达式" (3) 删除数据记录: sql="delete from 数据表 where 条件表达式" sql="delete from 数据表" (将数据表所有记录删除) (4) 添加数据记录: sql="insert into 数据表 (字段1,字段2,字段3 „) valuess (值1,值2,值3 „)" sql="insert into 目标数据表 select * from 源数据表" (把源数据表的记录添加到目标数 据表) (5) 数据记录统计函数: AVG(字段名) 得出一个表格栏平均值 COUNT(*|字段名) 对数据行数的统计或对某一栏有值的数据行数统计 MAX(字段名) 取得一个表格栏最大的值 MIN(字段名) 取得一个表格栏最小的值 SUM(字段名) 把数据栏的值相加 引用以上函数的方法: sql="select sum(字段名) as 别名 from 数据表 where 条件表达式" set rs=conn.excute(sql) 用 rs("别名") 获取统的计值,其它函数运用同上。 (5) 数据表的建立和删除: CREATE TABLE 数据表名称(字段1 类型1(长度),字段2 类型2(长度) „„ ) 例:CREATE TABLE tab01(name varchar(50),datetime default now()) DROP TABLE 数据表名称 (永久性删除一个数据表) Requery 支持 支持 支持 支持 Excel、Access、VB的结合应用 ---- 微软公司的Office系列办公软件相信已是众所周知,其中Excel强大的统计制表功能、Access功能完备的数据处理能力深受众多用户所喜爱。Visual Bsaic更是微软公司又一有力的产品,它简单易学,在Windows编程中的应用十分广泛。本文通过介绍数据处理及复杂表格的打印,来讨论VB与Excel及Access的结合运用。 ---- 由于笔者所在的公司员工众多,在进行职工养老保险缴费的计算工作时,若使用劳动局编制的软件(用Foxbase编写),无论是在管理或维护方面均显得力不从心。于是在公司领导的强烈要求下,决定由笔者构思重新编制。基本思路是:1.将所有员工资料输入Access进行处理,以便于维护。2.在Excel中预先制成有表头的空表(Access相对欠缺处理复杂表格的能力),对需要进行金额汇总或其他运算的单元格可直接输入公式。3.在VB中编写程序代码,从Access中提取数据填入Excel对应表格相应的单元格,并输出至打印机。 ---- 部分窗体及源程序代码如下: ---- 1(程序主模块 ---- 定义Excel、Access对象变量,显示系统启动画面,进入系统主程序界面。强调一下,在编写程序之前须加入对Excel及Access库函数的引用,具体操作是:选择菜单栏'工程'\'引用„',将'可使用的引用'列表框内'Microsoft Access 8.0 Object Library'和 'Microsoft Excel 8.0 Object Library'两项前的复选框标为选中,按"确定"返回。 mdsMain.bas '定义数据库记录集及Excel对象变量 Public ex As New Excel.Application Public exwbook As Excel.Workbook Public exsheet As Excel.Worksheet Public mydatabase As Database Public myrecordset1 As Recordset [定义记录集] „„ „„ Public Opt As Integer '报表选项 [Opt为frmSelreport.frm返回值] Public isYN As Boolean Sub Main() Load frmSplash frmSplash.Show frmSplash.Label2.Caption = " 系统正在加载Access数据库..." Set mydatabase = OpenDatabase("c:\sbda\sbda.mdb") Set myrecordset1 = mydatabase.OpenRecordset ("报表打印(一)") [此处对记录集赋值] „„ „„ frmSplash.Label2.Caption = " 系统正在加载Excel电子表格..." Set ex = CreateObject("excel.application") Set exwbook = ex.Workbooks.Open("c:\sbda\sbda.xls") Load FrmInput '将数据输入窗体加载到内存中 Unload frmSplash Load FrmMain '将主程序界面加载到内存中 End Sub ---- 2(报表打印模块 ---- 其中ExcelDoForVB1()是一子程序,由prnProess()调用,作用是从Access中提取所 需数据资料,填入Excel对应工作表(Worksheet)的相应单元格(Cells)中,然后打印已 填入数据的表格;prnProess()则负责实现对VB通用对话框(Commom Dialog)中打印功能 的控制。 mdlPrint.bas Option Explicit '定义循环计数变量 Public nRow As Integer, nCol As Integer, nBtoE As Integer '定义变量接收打印对话框返回值 Public BeginPage, EndPage, NumCopies '程序运行时需进行判断的各种标志 Public nflag, Flag, ifNum '数据记录集中指针移动数 Public PageN As Integer, n As Integer 'bar1为进度条 Public bar1 As Object Sub prnProess() '控制通用对话框打印功能 Set bar1 = FrmPrint.PgsBar1 '进度条 On Error GoTo errhandle: If Flag = 0 Then '当打印对话框中选"全部"时 Select Case Opt '选择需要打印的表格 Case 1 nflag = 1 myrecordset1.MoveFirst myrecordset1.MovePrevious PageN = 1 Do While nflag = 1 Call ExcelDoForVB1 '数据填入Excel单元格打印 PageN = PageN + 1 Loop Case 2 „„ „„ End Select Else If Flag = 2 Then ' 当打印对话框中选"页"时 If EndPage - BeginPage = 0 Then ifNum = 0 Else If EndPage - BeginPage > 0 Then ifNum = 1 Else ifNum = 2 End If End If Select Case ifNum Case 2 Exit Sub Case 0 Select Case Opt ' 选择需要打印的表格 Case 1 myrecordset1.MoveFirst n = (BeginPage - 1) * (49 - 4 + 1) - 1 myrecordset1.Move n PageN = BeginPage Call ExcelDoForVB1 '数据填入Excel单元格并打印 Case 2 „„ „„ End Select Case 1 Select Case Opt '选择需要打印的表格 Case 1 myrecordset1.MoveFirst n = (BeginPage - 1) * (49 - 4 + 1) - 1 myrecordset1.Move n PageN = BeginPage For nBtoE = BeginPage To EndPage Call ExcelDoForVB1 '填入Excel单元格并打印 PageN = PageN + 1 Next nBtoE Case 2 „„ „„ End Select End Select End If End If FrmMain.Visible = True Exit Sub errhandle: FrmPrint.Visible = False FrmMain.Visible = True End Sub ---- 注意,下段仅通过ExcelDoForVB1()对"报表(一)"的处理,来说明数据填入Excel 并打印的整个过程。 Sub ExcelDoForVB1() '打印报表(一) FrmPrint.Visible = True Set exsheet = exwbook.Worksheets("sheet1") ex.Sheets("Sheet1").Select ex.Range("A4:U49").Select ex.Selection.ClearContents ex.Range("A4").Select bar1.Min = 0 bar1.Max = 45 For nRow = 4 To 49 bar1.Value = nRow - 4 '进度显示栏进程 myrecordset1.MoveNext If myrecordset1.EOF Then nflag = 0 Exit For End If For nCol = 1 To 21 exsheet.Cells(nRow, nCol) = myrecordset1.Fields(nCol - 1) Next nCol Next nRow exsheet.Cells(52, 21) = "第 " + CStr(PageN) + " 页" FrmPrint.Visible = False bar1.Value = 0 ActiveWindow.SelectedSheets.PrintOut Copies:=NumCopies End Sub ---- 虽然本文针对的是大多数已熟练掌握数据库技术,且精通编程之道的朋友们。但笔 者认为仍有必要提一提将数据输入Access的过程,因为编出来的软件更多是面向各类普通 用户,对他们来说最要紧的是好用,而其间的一系列关联并不想深究。所以设计一个好的输 入界面十分有必要,在设计时可以运用VB提供的Data控件,当然若是考虑性能的话还可 以用代码直接操纵数据。关于如何使用Data控件访问数据库,在Visual Basic的联机手册 (Online book)中有很详细的说明,此处不再赘述。 ---- 文中的所有程序在Visual Bsaic5.0中文专业版及Office97中文版中调试通过。 如下代码可以做到真正居中显示 Private Sub Form_Load() DoCmd.Echo False Dim x, y As Integer DoCmd.Maximize x = Me.WindowWidth y = Me.WindowHeight DoCmd.Restore DoCmd.Echo True Move (x - Me.WindowWidth) / 2, (y - Me.WindowHeight) / 2 End Sub 打开、关闭“计算器” 1(如何控制设计, 新建一表单,在表单中放入两个按钮,其Caption分别为“打开”(即启动“计算器”) 和“关闭”(退出结束),且为它们分别添加Click事件处理。详见表单Form1及单元文件 Unit1。 其中,最主要的几条语句有: fwnd:=FindWindow('SciCalc','计算器'); 函数原型为(详见Delphi的帮助): HWND FindWindow( LPCTSTR lpClassName, // pointer to class name LPCTSTR lpWindowName // pointer to window name ); 此处,'SciCalc' 为计算器的类名,'计算器'为计算器的窗口标题} setWindowPos(fwnd,HWND_NOTOPMOST,0,0,0,0,SWP_SHOWWINDOW or SWP_NOSIZE or SWP_NOMOVE); 函数原型为: BOOL SetWindowPos( HWND hWnd, // handle of window HWND hWndInsertAfter, // placement-order handle int X, // horizontal position int Y, // vertical position int cx, // width int cy, // height UINT uFlags // window-positioning flags ); ShowWindow(fwnd,SW_RESTORE); //显示已打开的「计算器」 函数原型为: BOOL ShowWindow( HWND hWnd, // handle of window int nCmdShow // show state of window ); Ret:=WinExec('c:\windows\calc.exe',SW_SHOWNORMAL); //启动计算器 函数原型为: UINT WinExec( LPCSTR lpCmdLine, // address of command line UINT uCmdShow // window style for new application ); 运行“计算器”程序并检测返回值(从而利用返回值来判断可能发生的错误) 2(如何明确应用程序的“类名”, 要控制应用程序,首先必须明确应用程序的“类名”。“类”的概念,Delphi的程序已经 非常清楚,如:新建一表单Form1,该表单的“类名”为TForm1。那么其它Windows程序 的“类名”如何确定呢, 值得一喜的是,Delphi提供了一实用工具Winsight,它正如一面照妖镜,不论何方妖怪, 均会显露出它们的“类名”。 使用Winsight的方法如下: ?运行Winsight(程序名为ws32.exe,与主文件delphi32.exe同一目录),见图?; ?从Winsight的菜单中选择“间谍”中的“跟随焦点”,见图?; ?运行“计算器”程序; ?在Winsight中显示出了目标,如图?所示。 软件环境:中文Win98/中文Delphi5.0。 打印格式如何控制横打 打印格式如何控制横打 Private Sub com_rpt_hue_exist_qry_cust_Click() On Error GoTo Err_com_rpt_hue_exist_qry_cust_Click Dim stdocname As String Dim prt As Printer Set prt = Application.Printers(0) prt.PaperSize = acPRPSA4 prt.Orientation = acPRORLandscape stdocname = "hue_exist_mount_qry_cust" DoCmd.OpenReport stdocname, acPreview Reports(stdocname).Printer = prt Exit_com_rpt_hue_exist_qry_cust_Click: Exit Sub Err_com_rpt_hue_exist_qry_cust_Click: MsgBox Err.Description Resume Exit_com_rpt_hue_exist_qry_cust_Click End Sub 创建完美报表 Access作为Microsoft Office办公软件包中的一部分,以其友好的操作界面和卓越的数据管理能力而日益成为中小型管理信息系统的理想开发环境,在各行各业得到了广泛的应用。但在应用中我们发现,Access在报表输出上还存在一些不足:尽管它可以很好地处理一些基于页面的报表,但对一些复杂报表或一些特殊报表的处理能力却很难令人满意,这主要是由于Access系统附带的报表设计器太过直观,缺少了程序设计和文字处理所需的必要的灵活性。而Word作为Microsoft Office家族中的重要成员——字处理器,其强大的文字处理功能正好可以弥补Access在报表方面的不足。这就使得我们自然而然地想到将Access与 Word有机地结合起来,利用Access的数据处理功能进行数据的录入、查询、存储,而利用Word的字处理功能进行各种报表的打印输出。幸好,微软在设计Office的时候就已经为我们提供了一种在诸如Access、Word、Excel等应用程序之间通信的机制,使得这种想法得以实现。 一、基本原理 对于一些复杂的或有特殊要求的查询,用ADO(ActiveX数据对象)来处理要比用Access本身提供的查询管理器更灵活一些。所以我们的基本思路是:用ADO执行一条或多条特定的SQL查询,生成我们所需要的一个或多个Recordset,再将这些Recordset中的数据逐条输出到Word文档,然后就可以用程序或手工控制Word文档的格式,达到我们的特殊要求。这听起来挺麻烦,可只要了解了其工作原理,实际操作却很简单。下面就分别以在Access中和在Word中的具体操作为例进行介绍。 二、在Access中应用ADO将数据输出到Word 1. 系统配置 系统软件:Microsoft Windows 9x/NT/2000;Microsoft Access 2000;Microsoft Word 2000。 样例数据库:“C:\Program Files\Microsoft Office\Office\Samples\Northwind.mdb”,Office 2000中包含的例子。可将其中的“产品”表复制到一个新的数据库中,如“D:\db1.mdb”。 窗 体:在数据库“D:\db1.mdb”中新建窗体“窗体1”,其中只包含1个命令按钮“命令0”。 引用ADO:按Alt+F11进入Visual Basic编辑器,执行“工具”->“引用”命令,在弹出的引用窗体中选择“Microsoft ActiveX Data Objects 2.1”或更高版本。 引用Word:再次执行命令“工具”->“引用”,在弹出的引用窗体中选择“Microsoft Word 9.0 Object Library”。 2. 代码详解 在“窗体1”的设计模式下右键单击“命令0”按钮,选择“事件生成器”,进入Visual Basic编辑器,创建过程“Private Sub 命令0_Click()”,其代码如下: Sub 命令0_Click() '输入表格标题 Title = InputBox(vbCrLf & vbCrLf & "请输入表格标题:", "表格标题", "XX公司产品报价单") If Title = "" Then Title = "XX公司产品报价单" '步骤1:建立数据连接cnn '由于数据库已经打开,所以直接应用CurrentProject.Connection就可以建立连接 Set cnn = New ADODB.Connection Set cnn = CurrentProject.Connection '步骤2:用SQL语句创建记录集rs Set rs = New ADODB.Recordset '设定游标类型与锁定类型 rs.CursorType = adOpenKeyset rs.LockType = adLockOptimistic '制定特定的查询条件,可以是任何有效的SQL查询,甚至包括多表、多条件等复杂的查询,查询条件也常常从窗体取得 SQL = "select 产品名称,单位数量,单价,库存量 from 产品 where 单价>10.00" '创建记录集rs rs.Open SQL, cnn '统计字段数及记录数 total_fields = rs.Fields.Count total_records = rs.RecordCount '步骤3:建立Word文档对象 Set mywdapp = CreateObject("word.application") '调整Word窗口大小 mywdapp.WindowState = wdWindowStateNormal '生成新的Word文档实例 mywdapp.Documents.Add '设置视图为页面视图 mywdapp.ActiveWindow.View.Type = wdPrintView '转到Word视图,显示文档生成过程 mywdapp.Visible = True mywdapp.Activate '设置文档(表格)字体 mywdapp.ActiveDocument.Range.Font.Size = "9" '步骤4:将记录集rs中的字段名称和字段内容输出到Word,各字段之间用制表符分隔 '输出字段名称 For I = 0 To total_fields - 2 mywdapp.Selection.TypeText Text:=rs.Fields(I).Name & vbTab Next I '最后一个字段名称后加回车符 mywdapp.Selection.TypeText Text:=rs.Fields(total_fields - 1).Name & vbCrLf '逐条输出字段内容 Do While Not rs.EOF For I = 0 To total_fields - 2 tmpstr = rs.Fields(I).value If rs.Fields(I).Name = "单价" Then tmpstr = Format(tmpstr, "####.00") End If mywdapp.Selection.TypeText Text:=tmpstr & vbTab Next I '一条记录的最后一个字段后加回车符 mywdapp.Selection.TypeText Text:=rs.Fields(total_fields - 1).value & vbCrLf rs.MoveNext Loop '步骤5:关闭记录集 rs.Close Set rs = Nothing '步骤6:对Word中的数据进行格式化处理 '选定文本,将其转换为表格 '设置视图为普通视图 mywdapp.ActiveWindow.View.Type = wdNormalView '将光标移动到文档末尾 mywdapp.Selection.EndKey Unit:=wdStory '删除文档末尾多余的回车符 mywdapp.Selection.Delete Unit:=wdCharacter, Count:=1 '选中全部内容 mywdapp.Selection.WholeStory '将所选内容转换为表格 mywdapp.Selection.ConvertToTable Separator:=wdSeparateByTabs, DefaultTableBehavior:=wdWord8TableBehavior '将光标移动到文档开头 mywdapp.Selection.HomeKey Unit:=wdStory '选定表格对象 Set Temp_Table = mywdapp.ActiveDocument.Tables(1) '根据需要对表格进行处理,这是制作表格格式的关键,可反复调试 '本例只简单地设置了表格居中、自动调整表格列宽、表头居中、标题行重复、设置表 格边框线、设置表格纵向居中 Temp_Table.Rows.Alignment = wdAlignRowCenter Temp_Table.AutoFitBehavior wdAutoFitContent Temp_Table.Rows(1).Range.ParagraphFormat.Alignment = wdAlignParagraphCenter Temp_Table.Rows(1).Range.Rows.HeadingFormat = wdToggle Temp_Table.Borders(wdBorderLeft).LineWidth = wdLineWidth150pt Temp_Table.Borders(wdBorderRight).LineWidth = wdLineWidth150pt Temp_Table.Borders(wdBorderTop).LineWidth = wdLineWidth150pt Temp_Table.Borders(wdBorderBottom).LineWidth = wdLineWidth150pt Temp_Table.Range.Cells.VerticalAlignment = wdCellAlignVerticalCenter '将光标移动到文档开头 mywdapp.Selection.HomeKey Unit:=wdStory '拆分表格 mywdapp.Selection.SplitTable mywdapp.Selection.Font.Name = "黑体" '插入标题 mywdapp.Selection.TypeText Text:=Title & vbCrLf mywdapp.Application.ScreenRefresh '刷屏 '转到Acdess视图,显示结束对话框 mywdapp.Visible = False Msg = "数据提取完毕。" & vbCrLf & vbCrLf Msg = Msg & "总记录数=" & total_records & " 条" MsgBox Msg, vbOKOnly, "数据提取完毕" '转到Word视图,显示文档 mywdapp.Visible = True mywdapp.Activate End Sub 动态余额问题--之1,看这里了 dsum解决方案 在模块里建立下面这个函数。 Public Function Balance(d As Double, DomainName As String) As Currency Dim a As Currency Dim b As Currency a = Nz(DSum(DomainName & "![收入金额]", DomainName, "[余额条件] <= " & d)) b = Nz(DSum(DomainName & "![支出金额]", DomainName, "[余额条件] <= " & d)) Balance = a - b If IsNull(Balance = True) Then Balance = 0 End Function 在写查询的时候这样写 dim strsql as string strsql="select 收入,支出,排列id,balance([排列id],'[C1]') as 余额 from c1 order by 排列 id" docmd.runsql strsql 《多个 Access 自定义函数《VBA》 'Access 自增函数及相关技巧 '检查指定文件是否存在 ***************** Code Start ******************* Function fIsFileDIR(stPath As String, _ Optional lngType As Long) _ As Integer 'Fully qualify stPath 'To check for a file ' ?fIsFileDIR("c:\winnt\win.ini") 'To check for a Dir ' ?fIsFileDir("c:\msoffice",vbdirectory) ' On Error Resume Next fIsFileDIR = Len(Dir(stPath, lngType)) > 0 End Function '***************** Code End ********************* '列表框中多选查询 '******************** Code Start ************************ Dim frm As Form, ctl As Control Dim varItem As Variant Dim strSQL As String Set frm = Form!frmMyForm Set ctl = frm!lbMultiSelectListbox strSQL = "Select * from Employees where EmpID=" 'Assuming long EmpID is the bound field in lb 'enumerate selected items and 'concatenate to strSQL For Each varItem In ctl.ItemsSelected strSQL = strSQL & ctl.ItemData(varItem) & " OR EmpID=" Next varItem 'Trim the end of strSQL strSQL=left$(strSQL,len(strSQL)-12)) '******************** Code end ************************ 屏蔽PageUP , PageDown '************ Code Start ********** Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer) '33 - PgUp; 34 - PgDown; 9 - Tab; 18=Alt Select Case KeyCode Case 33, 34, 9, 18 KeyCode = 0 Case Else 'Debug.Print KeyCode, Shift End Select End Sub '************ Code End ********** ''窗体参数 DoCmd.OpenForm "SomeFormB", , , , , , Me.Name DoCmd.Close acForm, Me.OpenArgs '更新保存提示. ****************** Code Start ****************** Private Sub Form_BeforeUpdate(Cancel As Integer) Dim strMsg As String strMsg = "Data has changed." strMsg = strMsg & "@Do you wish to save the changes?" strMsg = strMsg & "@Click Yes to Save or No to Discard changes." If MsgBox(strMsg, vbQuestion + vbYesNo, "Save Record?") = vbYes Then 'do nothing Else DoCmd.RunCommand acCmdUndo 'For Access 95, use DoMenuItem instead 'DoCmd.DoMenuItem acFormBar, acEditMenu, acUndo, , acMenuVer70 End If End Sub '子窗口无数据时,隐藏 '*********** Code Start ********** Private Sub Form_Current() With Me!SubformName.Form .Visible = (.RecordsetClone.RecordCount > 0) End With End Sub '*********** Code End ********** '窗口增加时钟 ***************** Code Start *************** Private Sub Form_Timer() Me!lblClock.Caption = Format(Now, "dddd, mmm d yyyy, hh:mm:ss AMPM") End Sub Private Sub cmdClockStart_Click() Me.TimerInterval = 1000 End Sub Private Sub cmdClockEnd_Click() Me.TimerInterval = 0 End Sub '***************** Code End *************** '引用外部数据库的窗体 '************ Code Start ************* 'Private Declare Function apiSetForegroundWindow Lib "user32" _ Alias "SetForegroundWindow" _ (ByVal hwnd As Long) _ As Long Private Declare Function apiShowWindow Lib "user32" _ Alias "ShowWindow" _ (ByVal hwnd As Long, _ ByVal nCmdShow As Long) _ As Long Private Const SW_MAXIMIZE = 3 Private Const SW_NORMAL = 1 Function fOpenRemoteForm(strMDB As String, _ strForm As String, _ Optional intView As Variant) _ As Boolean Dim objAccess As Access.Application Dim lngRet As Long On Error GoTo fOpenRemoteForm_Err If IsMissing(intView) Then intView = acViewNormal If Len(Dir(strMDB)) > 0 Then Set objAccess = New Access.Application With objAccess lngRet = apiSetForegroundWindow(.hWndAccessApp) lngRet = apiShowWindow(.hWndAccessApp, SW_NORMAL) 'the first call to ShowWindow doesn't seem to do anything lngRet = apiShowWindow(.hWndAccessApp, SW_NORMAL) .OpenCurrentDatabase strMDB .DoCmd.OpenForm strForm, intView Do While Len(.CurrentDb.Name) > 0 DoEvents Loop End With End If fOpenRemoteForm_Exit: On Error Resume Next objAccess.Quit Set objAccess = Nothing Exit Function fOpenRemoteForm_Err: fOpenRemoteForm = False Select Case Err.Number Case 7866: 'mdb is already exclusively opened MsgBox "The database you specified " & vbCrLf & strMDB & _ vbCrLf & "is currently open in exclusive mode. " & vbCrLf _ & vbCrLf & "Please reopen in shared mode and try again", _ vbExclamation + vbOKOnly, "Could not open database." Case 2102: 'form doesn't exist MsgBox "The Form '" & strForm & _ "' doesn't exist in the Database " _ & vbCrLf & strMDB, _ vbExclamation + vbOKOnly, "Form not found" Case 7952: 'user closed mdb fOpenRemoteForm = True Case Else: MsgBox "Error#: " & Err.Number & vbCrLf & Err.Description, _ vbCritical + vbOKOnly, "Runtime error" End Select Resume fOpenRemoteForm_Exit End Function '************ Code End ************* '关闭所有窗体 Dim intx As Integer Dim intCount As Integer intCount = Forms.Count - 1 For intx = intCount To 0 Step -1 DoCmd.Close acForm, Forms(intx).Name Next '*************OR************** For intx = intCount To 0 Step -1 If Forms(intx).Name <> "MyFormToKeepOpen" Then DoCmd.Close acForm, Forms(intx).Name End If Next '复制当前打开的数据库 '********** Code Start ************* Private Type SHFILEOPSTRUCT hwnd As Long wFunc As Long pFrom As String pTo As String fFlags As Integer fAnyOperationsAborted As Boolean hNameMappings As Long lpszProgressTitle As String End Type Private Const FO_MOVE As Long = &H1 Private Const FO_COPY As Long = &H2 Private Const FO_DELETE As Long = &H3 Private Const FO_RENAME As Long = &H4 Private Const FOF_MULTIDESTFILES As Long = &H1 Private Const FOF_CONFIRMMOUSE As Long = &H2 Private Const FOF_SILENT As Long = &H4 Private Const FOF_RENAMEONCOLLISION As Long = &H8 Private Const FOF_NOCONFIRMATION As Long = &H10 Private Const FOF_WANTMAPPINGHANDLE As Long = &H20 Private Const FOF_CREATEPROGRESSDLG As Long = &H0 Private Const FOF_ALLOWUNDO As Long = &H40 Private Const FOF_FILESONLY As Long = &H80 Private Const FOF_SIMPLEPROGRESS As Long = &H100 Private Const FOF_NOCONFIRMMKDIR As Long = &H200 Private Declare Function apiSHFileOperation Lib "Shell32.dll" _ Alias "SHFileOperationA" _ (lpFileOp As SHFILEOPSTRUCT) _ As Long Function fMakeBackup() As Boolean Dim strMsg As String Dim tshFileOp As SHFILEOPSTRUCT Dim lngRet As Long Dim strSaveFile As String Dim lngFlags As Long Const cERR_USER_CANCEL = vbObjectError + 1 Const cERR_DB_EXCLUSIVE = vbObjectError + 2 On Local Error GoTo fMakeBackup_Err If fDBExclusive = True Then Err.Raise cERR_DB_EXCLUSIVE strMsg = "Are you sure that you want to make a copy of the database?" If MsgBox(strMsg, vbQuestion + vbYesNo, "Please confirm") = vbNo Then _ Err.Raise cERR_USER_CANCEL lngFlags = FOF_SIMPLEPROGRESS Or _ FOF_FILESONLY Or _ FOF_RENAMEONCOLLISION strSaveFile = CurrentDb.Name With tshFileOp .wFunc = FO_COPY .hwnd = hWndAccessApp .pFrom = CurrentDb.Name & vbNullChar .pTo = strSaveFile & vbNullChar .fFlags = lngFlags End With lngRet = apiSHFileOperation(tshFileOp) fMakeBackup = (lngRet = 0) fMakeBackup_End: Exit Function fMakeBackup_Err: fMakeBackup = False Select Case Err.Number Case cERR_USER_CANCEL: 'do nothing Case cERR_DB_EXCLUSIVE: MsgBox "The current database " & vbCrLf & CurrentDb.Name & vbCrLf & _ vbCrLf & "is opened exclusively. Please reopen in shared mode" & _ " and try again.", vbCritical + vbOKOnly, "Database copy failed" Case Else: strMsg = "Error Information…" & vbCrLf & vbCrLf strMsg = strMsg & "Function: fMakeBackup" & vbCrLf strMsg = strMsg & "Description: " & Err.Description & vbCrLf strMsg = strMsg & "Error #: " & Format$(Err.Number) & vbCrLf MsgBox strMsg, vbInformation, "fMakeBackup" End Select Resume fMakeBackup_End End Function Private Function fCurrentDBDir() As String 'code courtesy of 'Terry Kreft Dim strDBPath As String Dim strDBFile As String strDBPath = CurrentDb.Name strDBFile = Dir(strDBPath) fCurrentDBDir = Left(strDBPath, InStr(strDBPath, strDBFile) - 1) End Function Function fDBExclusive() As Integer Dim db As Database Dim hFile As Integer hFile = FreeFile Set db = CurrentDb On Error Resume Next Open db.Name For Binary Access Read Write Shared As hFile Select Case Err Case 0 fDBExclusive = False Case 70 fDBExclusive = True Case Else fDBExclusive = Err End Select Close hFile On Error GoTo 0 End Function '************* Code End *************** '代替replace函数 '************ Code Start ********** Function fstrTran(ByVal sInString As String, _ sFindString As String, _ sReplaceString As String) As String Dim iSpot As Integer, iCtr As Integer Dim iCount As Integer iCount = Len(sInString) For iCtr = 1 To iCount iSpot = InStr(1, sInString, sFindString) If iSpot > 0 Then sInString = Left(sInString, iSpot - 1) & _ sReplaceString & _ Mid(sInString, iSpot + Len(sFindString)) Else Exit For End If Next fstrTran = sInString End Function '************* Code End *************** 在一个窗体中执行另一窗体的子程序 DoCmd.OpenForm "窗体2" Call Forms("窗体2").aaa 通过编程添加和删除用户和组 为数据库设置了安全性后,您可能需要使用用户和组。以下各节展示了其中的一些技巧。 在使用以下各节介绍的过程之前,可能需要设置对 Microsoft ADO Ext 2.5 for DDL and Security 库的引用(如果尚未设置): 在 Visual Basic 编辑器中,指向“工具”菜单中的“引用”。将显示“引用”对话框。 选中 Microsoft ADO Ext 2.5 for DDL and Security 复选框。 添加和删除用户 以下过程将创建一个新的用户帐户,然后将其追加到用于当前数据库的工作组信息文件 中的默认 Users 组。 注意:要在 Access 中使用下面的示例,您需要作为 Admins 组的成员登录并打开一个 数据库。在下面的过程中,您要确保工作组信息文件不包含在 strUser 中指定了其名称的用 户。例如,您可以先调用 DeleteUser 子例程来确保这一点。 请看以下代码: Private Function AddUser(ByVal strUser As String, _ ByVal strPID As String, _ Optional ByVal strPwd As String) As Boolean Dim catDB As ADOX.Catalog On Error GoTo AddUser_Err ' 实例化 Catalog 对象。 Set catDB = New ADOX.Catalog With catDB ' 使用到当前数据库的连接打开 ' Catalog 对象。 .ActiveConnection = CurrentProject.Connection ' 创建新的用户帐户。 .Users.Append strUser, strPwd, strPID ' 向默认 Users 组追加新的用户帐户。 .Groups("Users").Users.Append strUser End With ' 关闭 Catalog 对象。 Set catDB = Nothing AddUser = True AddUser_Err: Msgbox Err.Number & ":" & Err.Description AddUser = False End Function 该过程首先为 Catalog 对象声明一个变量,然后实例化该对象。 注意:Catalog 对象是 Access 数据库文件中所有对象的容器。 然后,该过程打开到当前数据库的连接,并使用来自调用过程的参数,将新用户追加到 Catalog 对象的 Users 集合中。然后新用户被追加到默认的 Users 组。Users 集合包含了在 工作组信息文件中定义的数据库的所有用户。 要删除现有用户,可以使用以下过程: Private Function DeleteUser(ByVal strUser As String) As Boolean Dim catDB As ADOX.Catalog On Error GoTo DeleteUser ' 实例化 Catalog 对象。 Set catDB = New ADOX.Catalog With catDB ' 在当前数据库中打开 Catalog 对象。 .ActiveConnection = CurrentProject.Connection ' 删除 strUser。 .Users.Delete strUser End With ' 关闭 Catalog 对象。 Set catDB = Nothing DeleteUser = True DeleteUser_Err: Msgbox Err.Number & ":" & Err.Description DeleteUser = False End Function 此过程与前面的过程类似,只是使用了 Catalog 对象的 Delete 方法删除了在 strUser String 参数中指定的用户。 添加和删除组 添加组的过程与添加用户的过程类似。 Private Function AddGroup(ByVal strGroup As String, _ ByVal strPID As String) As Boolean Dim catDB As ADOX.Catalog On Error GoTo AddGroup_Err Set catDB = New ADOX.Catalog With catDB ' 在当前数据库中打开 Catalog 对象。 .ActiveConnection = CurrentProject.Connection ' 创建新的组。 .Groups.Append strGroup, strPID End With ' 关闭 Catalog 对象。 Set catDB = Nothing AddGroup = True AddGroup_Err: Msgbox Err.Number & ":" & Err.Description AddGroup = False End Function 此过程首先实例化 Catalog 对象,然后打开一个到当前数据库的连接。接下来,通过 使用来自调用过程的参数,将新组追加到 Catalog 对象的 Groups 集合。 要删除现有组,可以使用以下过程: Private Function DeleteGroup(ByVal strGroup As String) As Boolean Dim catDB As ADOX.Catalog On Error GoTo DeleteGroup_Err Set catDB = New ADOX.Catalog With catDB ' 在当前数据库中打开 Catalog 对象。 .ActiveConnection = CurrentProject.Connection ' 删除 strGroup。 .Groups.Delete strGroup End With ' 关闭 Catalog 对象。 Set catDB = Nothing DeleteGroup = True DeleteGroup_Err: Msgbox Err.Number & ":" & Err.Description DeleteGroup = False End Function 此过程与前面的过程类似,只是使用了 Catalog 对象的 Delete 方法删除了在 strGroup String 参数中指定的组。 下面我们来看看如何通过编程设置对数据库对象的权限。 通过编程设置权限 要对数据库中的各种对象设置权限,可以使用 Group 或 User 对象的 SetPermissions 方法。在下面的过程中,我们首先撤消组的所有权限,然后再赋予组特定的权限。这样可以 确保该组只具有我们指定的权限: Private Function SetGroupPermissions(ByVal strGroup As String, _ ByVal strTable As String, ByVal strObjectType As String, _ ByVal strAction As String, _ ByVal strRevokeEnum As String) As Boolean Dim catDB As ADOX.Catalog On Error GoTo SetGroupPermissions_Err Set catDB = New ADOX.Catalog With catDB ' 在当前数据库中打开 Catalog 对象。 .ActiveConnection = CurrentProject.Connection ' 撤消组的所有权限。 .Groups(strGroup).SetPermissions tblTable, _ strObjectType, strAction, strRevokeEnum ' 赋予组特定的权限。 .Groups(strGroup).SetPermissions tblTable, _ strObjectType, strAction, _ adRightRead Or adRightInsert Or adRightUpdate End With ' 关闭 Catalog 对象。 Set catDB = Nothing SetGroupPermissions = True SetGroupPermissions_Err: Msgbox Err.Number & ":" & Err.Description SetGroupPermissions = False End Function 在当前数据库中打开一个 Catalog 对象后,我们使用了 Groups 集合的 SetPermissions 方法,撤消了该组对 Employees 表的所有权限。第一个参数是表的名称,第二个参数显示了对象的类型,这里是表。第三个参数指定了在设置权限时要执行的操作的类型,第四个参数是一个权限常数,指定了该组没有任何权限。我们已经撤消了该组对 Employees 表的所有权限,现在可以赋予其所希望的权限。 下一个语句的前三个参数与前一个语句中的相同。第四个参数是通过使用 Or 运算符,组合不同的权限常数所创建的一个值。这里,我们赋予了读取、插入和更新该表的权限。 要对指定类型(例如上述示例中的表)的所有新对象设置权限,请将用于赋予权限的语句中的第一个参数更改为 NULL 关键字。例如: ... catDB.Groups(strGroup).SetPermissions NULL, adPermObjTable ... 小结 在本文中,我们讨论了实现 Access 数据库不同保护级别的各种方法,介绍了共享级和用户级安全性。同时还介绍了如何使用 Access Security Wizard 以及如何通过编程来实现安全设置。 通过程序同步两个窗体的示例 当在“供应商”窗体上的供应商记录之间移动时,可能需要查看“产品列表”窗体上该供应商所供应的产品。可以用宏或 Microsoft Visual Basic 代码实现这一点。 使用宏 通过在宏中执行 OpenForm 操作响应“供应商”窗体的 Current 事件,可实现这一点。使“产品列表”窗体显示基础表的“供应商ID”字段与“供应商”窗体的“供应商ID”字段匹配的记录。操作的“Where 条件”参数设置如下: [供应商ID]=Forms![供应商]![供应商ID] 提示 如果并不总希望在“供应商”窗体的记录之间移动时显示“产品列表”窗体,请在宏中包含检查“产品列表”是否打开的条件表达式。 该条件表达式使用 IsLoaded 函数检查“产品列表”是否打开。IsLoaded 函数是“罗斯文”示例数据库中包含的示例函数过程 ,而不是内置的 Visual Basic 函数。 在创建如上的宏之后,应将“供应商”窗体的“成为当前”事件属性设置为该宏的名称。 使用 Visual Basic 代码 当在“供应商”窗体的记录中移动时,也许想要查看每个供应商在“产品”窗体中供应 的产品。在“供应商”窗体的 Form_Current 事件过程中,设置“产品”窗体的 FilterOn 和 Filter 属性: Private Sub Form_Current() ' Declare and set a variable to store the WHERE ' clause that describes the records you want to ' display. Dim strCond As String strCond = "SupplierID = Forms!Suppliers!SupplierID" ' Use the IsLoaded function from the Northwind ' sample database to check whether the Products ' form is open, then set the properties. If IsLoaded("Products") Then Forms![Products].FilterOn = True Forms![Products].Filter = strCond End If End Sub 《控件》如何注册第3方控件,》 如果是ActiveX控件: 1。打开ACCESS(任一文件) 2。在菜单栏上选工具/ActiveX控件,按注册 3。选择你的控件,按确定 4。然后打开或新建任一窗体, 5。在菜单栏上按插入/ActiveX控件 6。选择你刚注册的控件名,(名称可能不一样,要仔细找下) 7。按确定既可 如何最大化、最小化、隐藏Access主窗口;如何隐藏access 数据库窗体 通过一函数已定义的常量 fSetAccessWindow 实现。 该函数能用来完全隐藏 Access 窗口并将你自己的窗体显示在桌面上。在弹出式窗体的 Open 事件中使用 SW_HIDE 参数调用 fSetAccessWindow 函数实现。 注意:如果你隐藏了 Access 主窗口,要确定你有良好的出错处理。因为主窗口隐藏后, 一旦引发错误,并出错提示窗口上点击了“结束”按钮,这样不会使 Access 主窗口可见, 并退出你自己的窗体。推荐你在你的错误处理程序中使用 SW_SHOWNORMAL 参数调用 fSetAccessWindow 函数来显示 Access 主窗口。 如果由于别的原因,Access 主窗口不能显示,那么你将只能从任务栏中关闭你的 mdb, 在 Win 9x 中使用 Control-Alt-Delete 来结束任务,在 Win NT 、2000 或 XP 中,可以右 键单击任务栏选择任务管理器来选择该 mdb 结束任务。 '************ 代码开始 ********** Global Const SW_HIDE = 0 Global Const SW_SHOWNORMAL = 1 Global Const SW_SHOWMINIMIZED = 2 Global Const SW_SHOWMAXIMIZED = 3 Private Declare Function apiShowWindow Lib "user32" _ Alias "ShowWindow" (ByVal hwnd As Long, _ ByVal nCmdShow As Long) As Long Function fSetAccessWindow(nCmdShow As Long) ' 使用举例 ' 最大化 Access 窗口 ' fSetAccessWindow(SW_SHOWMAXIMIZED) ' 最小化 Access 窗口 ' fSetAccessWindow(SW_SHOWMINIMIZED) ' 隐藏 Access 窗口 ' fSetAccessWindow(SW_HIDE) ' 正常显示 Access 窗口 ' fSetAccessWindow(SW_SHOWNORMAL) ' Dim loX As Long Dim loFORM As Form On Error Resume Next Set loFORM = Screen.ActiveForm If Err <> 0 Then ' 没有活动窗体 no ActiveFORM If nCmdShow = SW_HIDE Then MsgBox "除非屏幕上有一个窗口,否则不能隐藏 Access 主窗口!" _ & vbCr & vbCr _ & "Cannot hide Access unless " _ & "a FORM is on screen" Else loX = apiShowWindow(hWndAccessApp, nCmdShow) Err.Clear End If Else If nCmdShow = SW_SHOWMINIMIZED And loFORM.Modal = True Then MsgBox "不能由屏幕上的 " & (loFORM.Caption + " ") & "窗体最小化 Access 主窗口!" _ & vbCr & vbCr _ & "Cannot minimize Access with " _ & (loFORM.Caption + " ") _ & "FORM on screen" ElseIf nCmdShow = SW_HIDE And loFORM.PopUp <> True Then MsgBox "不能由屏幕上的 " & (loFORM.Caption + " ") & "窗体隐藏 Access 主窗口!" _ & vbCr & vbCr _ & "Cannot hide Access with " _ & (loFORM.Caption + " ") _ & "FORM on screen" Else loX = apiShowWindow(hWndAccessApp, nCmdShow) End If End If fSetAccessWindow = (loX <> 0) End Function '************ 代码结束 ********** Global Code Option Compare Database Option Explicit Function IsLoaded(ByVal strFormName As String) As Integer ' Returns True if the specified form is open in Form view or Datasheet view. Const conObjStateClosed = 0 Const conDesignView = 0 If SysCmd(acSysCmdGetObjectState, acForm, strFormName) <> conObjStateClosed Then If Forms(strFormName).CurrentView <> conDesignView Then IsLoaded = True End If End If End Function
/
本文档为【[精品]用API禁止鼠标滚轮】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索