马艳红
摘要 本文作者经过多年的软件项目开发,总结了一种基于关系数据库的通用查询编程技巧。从程序的界面设计到源代码,每一处都作了详细的说明,编程者可以直接根据本文的内容做出自己的通用查询程序,并可以应用到其它的软件项目中,不会产生任何影响,使用方便灵活,使编程更具魅力! 关键词 VB,查询,数据库 一、通用查询功能的重要性 基于数据库的信息管理系统,最核心的功能是将数据存储到数据库中,并可以对数据进行增加、修改、删除、查询等功能。其中查询功能更是用户经常使用的功能,一个可改变条件的灵活、快捷、准确的查询会给用户带来极大的方便,也给软件本身带来了更大的价值。 二、通用查询的设计 1.对象的添加 在VB6.0环境中,建立一个标准的EXE工程,在工程的部件中添加ADO、MSHFlexGrid两个控件,然后在窗体中添加两个MSHFlexGrid对象,分别改名为Grid1和Grid2,添加三个Command按钮Command1,做成控件数组,添加两个Command按钮,分别改名为Cmd_confirm、Cmd_cancel,最后添加四个Combo控件Combo1,做成控件数组。 2.各控件的功能 Grid1:查询条件输入区,初始值设为2行,5列。 Grid2:查询结果显示区,可根据查询结果,自动调整行列,并显示记录。 Command1(0): Caption属性为“增加行”,具有为Grid1增加行数的功能。 Command1(1): Caption属性为“删除行”,具有为Grid1删除行数的功能。 Command1(2): Caption属性为“清除条件”,具有清除查询条件的功能。 Cmd_confirm:根据Grid1中的查询条件,查询数据的功能。 Cmd_cancel:退出查询功能。 Combo1(0):用于提供连接条件“And”和“or”。 Combo1(1):提供查询的内容(表或视图中字段对用的汉字别名)。 Combo1(2):提供查询的关系条件(“=”、“>”等)。 Combo1(3):提供Combo1(4)对应的查询字段的值。 Combo1(4):与Combo1(1)同步,提供查询的内容(表或视图中的字段名)。 3.设计后的界面 通用查询界面如下图所示:
图 通用查询界面 三、代码实现 1.自定义的对象及变量 Option Explicit Public cn As ADODB.Connection '数据库的连接对象 Public rs As ADODB.Recordset '数据库的记录集对象 Public strsumdemand As String '通用查询求和语句 Public strcondition As String '通用查询条件 '-------------------------需要编程者根据要查询的表或视图来改变的条件 Public constr As String '数据库连接字符串 Public strsql As String '传递查询条件(字段无汉字别名) Public strtable As String '传递查询表名 Public strdemand As String '通用查询语句(字段具有汉字别名) '------------------------------------------------------- 2.用户自定义过程 (1)完成对数据库连接对象cn的赋值,并打开,以备使用。 Public Sub opencn() '打开连接 Set cn = New ADODB.Connection ' constr字符串,用于编程者根据所使用的数据库不同(如Access、SQL Server),来修改成不同的连接字符串。本例中以cx.mdb为例。 constr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & App.Path & "\cx.mdb;Persist Security Info=False" cn.Open constr End Sub (2)完成对数据库连接对象cn关闭,及置空功能。 Public Sub closecn() cn.Close Set cn = Nothing End Sub (3)完成对数据库记录集对象rs的设置,并根据查询条件,对数据库进行查询,返回结果集。 Public Sub openrs(sqlstr As String) Set rs = New ADODB.Recordset With rs .ActiveConnection = cn .CursorLocation = adUseClient .CursorType = adOpenStatic .LockType = adLockBatchOptimistic .Source = sqlstr .Open Set .ActiveConnection = Nothing End With End Sub (4)完成对数据库连接记录集对象rs关闭,及置空功能。 Public Sub closers() rs.Close Set rs = Nothing End Sub (5)根据查询结果,将符合条件的记录添加到Grid2中,并显示。 Public Sub fillgrid() Dim j As Integer Dim i As Integer Dim m As Integer '记录集行值 Dim n As Integer '记录集列值 Dim rssum As ADODB.Recordset Opencn '调用子过程Opencn,打开数据库连接 '调用子过程Openrs,并传参数—查询的内容 openrs strdemand & strcondition closecn '调用子过程closecn,关闭数据库连接 Grid2.Clear '清空表格Grid2 Grid2.FormatString = "" '判断记录集中是否有记录,无记录跳出程序段 If rs.RecordCount <= 0 Then Exit Sub m = rs.RecordCount 'm变量用来记录记录集rs中的记录总数 n = rs.Fields.Count 'n变量用来记录记录集rs的字段的总数 rs.MoveFirst '---设置Grid2的0至n-1列的对齐方式和文本内容 For i = 0 To n - 1 Grid2.FormatString = Grid2.FormatString & " |< " & rs.Fields(i).Name Next '------------------------------------------------------- Grid2.Rows = m + 1 '设置Grid2的总行数 Grid2.Cols = n + 1 '设置Grid2的总列数 '---将查询到的记录添加到Grid2中 For i = 1 To m '------------------------------行循环 For j = 1 To n '=====================列循环 Grid2.TextMatrix(i, j) = rs.Fields(j - 1).Value & "" If m <= 100 Then If i Mod 2 = 0 Then Grid2.Col = j Grid2.Row = i Grid2.CellBackColor = &HFEFBDE End If End If Next j '================================= rs.MoveNext Next i '------------------------------------ '---------------向Grid2中添加查询到的记录 If strsumdemand <> "" Then opencn Grid2.Rows = Grid2.Rows + 1 Grid2.TextMatrix(Grid2.Rows - 1, 1) = "合计" Set rssum = New ADODB.Recordset rssum.Open strsumdemand & strcondition, cn, adOpenKeyset, adLockReadOnly For j = 1 To n For i = 0 To rssum.Fields.Count - 1 If Grid2.TextMatrix(0, j) = rssum.Fields(i).Name Then Grid2.TextMatrix(Grid2.Rows - 1, j) = _ & rssum.Fields(i).Value & "" End If Next i Next j closecn End If Grid2.MergeCells = flexMergeRestrictColumns Grid2.MergeCol(1) = True Me.Caption = Mid(Me.Caption, 1, InStr(Me.Caption, "表")) & "(共有" & Grid2.Rows - 1 & "条记录)" '----------------------------------------------------------- End Sub (6)根据参数com和rs,向combobox中添加值 Public Sub fillcom1(com As ComboBox, rs As ADODB.Recordset)'填充combobox com.Clear If rs.RecordCount <= 0 Then Exit Sub rs.MoveFirst Do Until rs.EOF com.AddItem (rs.Fields(0).Value) & "" rs.MoveNext Loop rs.MoveFirst End Sub 3.窗体的加载事件 Private Sub Form_Load() ' 给strsql变量赋值,值为SELECT语句,参考格式如下,只有字段名,字段无别名,这是为了与界面用户操作的查询字段同步,给编程者提供的字段名称 strsql = "SELECT STUDENT_TBL.STUID, STUDENT_TBL.STUname, STUDENT_TBL.STUsorce, STUDENT_TBL.STUchive FROM STUDENT_TBL" ' 给strdemand变量赋值,值为SELECT语句,参考格式如下,给字段取别名是为了在选择条件的界面给用户提供汉字的参考 strdemand = "SELECT STUDENT_TBL.STUID as 学号, STUDENT_TBL.STUname as 姓名, STUDENT_TBL.STUsorce as 课程, STUDENT_TBL.STUchive as 成绩 FROM STUDENT_TBL" ' 给strtable变量赋值,值为要查询的表名或视图名 strtable = "STUDENT_TBL" strsumdemand = "" Dim i As Integer ' --------------给Grid1初始化,设置列宽、单元格对齐方式 Grid1.FormatString = " 逻辑符|^ 列 名 |^ 运算符 |^ 数据值 |" Grid1.ColWidth(4) = 0 Grid1.ColWidth(3) = 2500 Grid1.ColWidth(2) = 1000 Grid1.ColWidth(1) = 1850 Grid1.ColWidth(0) = 1000 For i = 0 To 3 Grid1.Row = 0 Grid1.Col = i Grid1.CellAlignment = 4 Next i ' ----------------------------------------------------- Opencn '调用子过程Opencn,打开数据库连接 openrs strdemand '调用子过程Openrs,并传参数—查询的内容 ' --------------------向Combo1(1)中添加strdemand字符串中字段别名 For i = 0 To rs.Fields.Count - 1 Combo1(1).AddItem rs.Fields(i).Name Next i ' --------------------向Combo1(4)中添加strsql字符串中字段名 openrs strsql For i = 0 To rs.Fields.Count - 1 Combo1(4).AddItem rs.Fields(i).Name Next i closers closecn ' ----------------------初始化Combo1(2) With Combo1(2) .AddItem " = " .AddItem " > " .AddItem " < " .AddItem " >= " .AddItem " <= " .AddItem " <> " .AddItem " like " End With ' -----设置Combo1的0--3各元素与Grid1的0--3各列的宽度相同 Combo1(0).Width = 1000 Combo1(1).Width = 1850 Combo1(2).Width = 1000 Combo1(3).Width = 2500 End Sub 4.取消按钮的单击事件 Private Sub Cmd_cancel_Click() Unload Me End Sub 5.确定按钮的单击事件 Private Sub Cmd_confirm_Click() Dim i As Integer ' -----根据Combo1(3)的特殊值,修改Grid1当前单元的文本 If Combo1(3).Visible = True Then If Combo1(3).Text = "True" Then Grid1.TextMatrix(Grid1.Row, 3) = "1" ElseIf Combo1(3).Text = "Flase" Then Grid1.TextMatrix(Grid1.Row, 3) = "0" Else Grid1.TextMatrix(Grid1.Row, 3) = Combo1(3).Text End If End If strcondition = "" ' -----根据不同的关系运算,给strcondition变量赋值 If Grid1.Rows >= 2 And Grid1.TextMatrix(1, 1) <> "" Then If Grid1.TextMatrix(1, 2) = " like " Then strcondition = " where " & Grid1.TextMatrix(1, 4) & " like " & "'%" & Grid1.TextMatrix(1, 3) & "%'" Else strcondition = " where " & Grid1.TextMatrix(1, 4) & Grid1.TextMatrix(1, 2) & "'" & Grid1.TextMatrix(1, 3) & "'" End If For i = 2 To Grid1.Rows - 1 If Grid1.TextMatrix(i, 2) = " like " Then strcondition = strcondition & Grid1.TextMatrix(i, 0) & Grid1.TextMatrix(i, 4) & " like " & "'%" & Grid1.TextMatrix(i, 3) & "%'" Else strcondition = strcondition & Grid1.TextMatrix(i, 0) & Grid1.TextMatrix(i, 4) & Grid1.TextMatrix(i, 2) & "'" & Grid1.TextMatrix(i, 3) & "'" End If Next i End If ' -----调用过程Fillgrid,向Grid2中添加查询到的记录 Fillgrid
End Sub 6.Combo1的单击事件 Private Sub Combo1_Click(Index As Integer) ' ----控制Combo1(4)与Combo1(1)同步,并根据Combo1(1)中选的字段不同,向Combo1(3)中添加这一字段下的所有不重复的值 Dim tempsql As String If Index = 1 Then Combo1(4).ListIndex = Combo1(1).ListIndex Grid1.TextMatrix(Grid1.Row, 4) = Combo1(4).Text tempsql = "SELECT DISTINCT " & Combo1(4).Text & " from " & strtable opencn openrs tempsql closecn fillcom1 Combo1(3), rs End If Grid1.TextMatrix(Grid1.Row, Index) = Combo1(Index).Text If Grid1.Text = "True" Then Grid1.Text = "1" ElseIf Grid1.Text = "False" Then Grid1.Text = "0" End If End Sub 7.Command1的单击事件 Private Sub Command1_Click(Index As Integer) Dim i As Integer Select Case Index Case 0 '清除条件 Grid1.Rows = 2 For i = 0 To 4 Grid1.TextMatrix(1, i) = "" Next i Case 1 '增加行 Grid1.Rows = Grid1.Rows + 1 Case 2 '删除行 If Grid1.Rows > 2 Then Grid1.Rows = Grid1.Rows - 1 Else For i = 0 To 4 Grid1.TextMatrix(1, i) = "" Next i End If End Select End Sub 8.Grid1的EnterCell事件,控制Combo1在Grid1中出现的位置 Private Sub Grid1_EnterCell() Combo1(Grid1.Col).Visible = True Combo1(Grid1.Col).Left = Grid1.Left + Grid1.CellLeft Combo1(Grid1.Col).Top = Grid1.Top + Grid1.CellTop Combo1(Grid1.Col).ZOrder 0 End Sub 9.Grid1的LeaveCell事件 实现将Combo1中的文本内容添加到Grid1相应的单元格中。 Private Sub Grid1_LeaveCell() If Grid1.Row > 0 Then Grid1.Text = Combo1(Grid1.Col).Text If Grid1.Text = "True" Then Grid1.Text = "1" ElseIf Grid1.Text = "False" Then Grid1.Text = "0" End If Combo1(Grid1.Col).Visible = False End If End Sub 四、通用查询功能的验证 为验证以上程序功能,建立一个实验数据库CX.mdb,在此数据库中添加一个表STUDENT_TBL,结构如表1所示: 表1 STUDENT_TBL表结构
字段名 |
字段数据类型 |
主键 |
说明 |
STUID |
Varchar(12) |
Yes |
学生编号 |
STUname |
Varchar(50) |
|
学生姓名 |
STUsorce |
Varchar(20) |
|
课程 |
STUchive |
Varchar(50) |
|
成绩 | 然后向表中输入几条合理的数据,如表2所示: 表2 数据录入
学生编号 |
学生姓名 |
课程 |
成绩 |
200201050401 |
刘强 |
VB |
80.5 |
200201050402 |
李飞 |
VB |
95 |
200201050403 |
刘立 |
VC++ |
65 | 注意,在验证程序功能时,除了以上内容外,还要在代码中更改constr、strsql、strdemand、strtable的值。实现代码如下: constr字符串,用于编程者根据所使用的数据库不同(如Access、SQL Server),来修改成不同的连接字符串,本例中以cx.mdb为例: constr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & App.Path & "\cx.mdb;Persist Security Info=False"
strsql变量赋值,给编程者提供的字段名称: strsql = "SELECT STUDENT_TBL.STUID, STUDENT_TBL.STUname, STUDENT_TBL.STUsorce, STUDENT_TBL.STUchive FROM STUDENT_TBL" strdemand变量赋值,给用户提供汉字参考: strdemand = "SELECT STUDENT_TBL.STUID as 学号, STUDENT_TBL.STUname as 姓名, STUDENT_TBL.STUsorce as 课程, STUDENT_TBL.STUchive as 成绩 FROM STUDENT_TBL" strtable变量赋值,值为要查询的表名或视图名: strtable = "STUDENT_TBL" 修改以上代码后,将工程及子文件保存,然后运行程序,就会得到想要的功能。 五、结语 综上所述,利用以上代码,只需程序员根据程序要访问的数据库不同,改变连接字符串变量constr,就可以访问SQL Server、Access等类型的数据库,再根据要访问的表或试图的结构,写成SELECT语句的形式,对strsql、strdemand、strtable三个变量赋值,即可完成复杂的自由查询功能。同时这个功能代码,不会影响项目中其它程序功能,可作为单独的功能附加到程序中,从而增强程序的健壮性。可以说利用以上代码实现自由查询功能,既为程序员减轻了编程的压力,同时又获得了用户对开发者的认可,这也正是本文作者的意图,让程序员的编程更轻松,让软件为用户提供更灵活而强大的功能! 参考文献: [1] Microsoft Corporation著 微软[中国]有限公司 译.中文Visual Basic 6.0程序员指南 ,北京希望出版社1998.6. [2] 马艳红郑建伟等开发 国电电力物资信息管理系统.大连益友电脑有限公司,2002.3.
|