关系数据库数据集合靠的是表与表之间的关系联结起来的。很多情况下数据表是以父子关系联结,例如下面的这两张表:
[Bibliotheca]
ID Name
1 a
2 b
3 c
4 d
[Book]
ID CID Name Dept
1 1 a x
2 1 a y
3 1 a z
4 2 b x
5 2 b z
6 3 c z
7 4 d x
8 4 d z
9 4 d z
表一[Bibliotheca]为父表,表示书目信息,表二[Book]为子表,对应着具体的图书。书库中有一份书目,可以供借阅人查阅,每一份书目下都有1-N本具体的图书,而每本书实际上属于不同的部门所有,例如上表中名为《a》的书共有3本,分别属于x,y,z三个部门。
倘若需要做一个查询,显示每一书(应该是说名为*的书)分别属于哪些部门,数量是多少,要返回这样一个记录集就比较麻烦,该查询结果如同下表。
[result]
Name Dept List count
a x,y,z 3
b x,z 2
c z 1
d x,z 3
一般情况下,web页面要显示下面的结构的查询结果,需要使用一条select * from [Book] Order By CID返回整个Book表,然后循环整个Recordset表,遇到CID相同的Book,则数量递增,显示Dept Name,当遇到不同的CID的时候,显示Count,然后Count清零,显示新的Name。代码如下:
Count = 1
this_CID = 0
last_CID = 0
Do While Not rst.Eof
this_CID = rst("CID")
If this_CID <> last_CID Then Response.Write rst("Name") & " "
Response.Write rst("Dept") & ","
last_CID = this_CID
rst.moveNext
If rst.Eof Then
Response.Write " " & Count
Exit Do
Else
If last_CID <> rst("CID") Then
Response.Write " " & Count & "<br>"
Else
Count = Count + 1
End If
End If
Loop
这样的查询结果集的缺点是显而易见的,父表每一行对应子表的数据行少的话,还没有关系,一旦对应关系很多,就会产生大量的冗余数据。
要避免数据冗余这样的问题,还可以使用存储过程来建立临时表,通过几个查询来生成临时表数据,在Web页面中使用Recordset访问临时表即可。而临时表也有不少问题,首先会话断开的时候得清除临时表,其次只能用一个字段来表示关联的数据集合,在程序当中还得写分解程序。
上述问题就是我上周写的一个图书管理系统所遇到的,当然具体的表和查询的结果,略有出入,只是为了比较清晰明了的说明问题,结构大致相当即可。
我使用了微软的数据访问组件中的MSDataShape数据形成数据服务程序来解决显示父子表层次关系的问题,它完全避免了上述两种方法的弊端。
使用MSDataShape服务程序,产生的Recordset,不在是一个单表的结果集,而是一个具有分层结构的结果集和。
访问MSDataShape服务
为了访问MSDataShape服务程序,需要修改一下你的数据库联接字符串,由于MSDataShape是OLE DB服务程序的一部分,因此原先的数据库联接必须是OLE DB提供的连接,而无法使用ODBC提供的连接。
原先的OLE DB数据库联接字符串如果为:
ConnString = "Provider=SQLOLEDB;Data Source=myDBServer;Initial Catalog=TestDB"
那么只需要在ConnString前面加上串字符"Provider=MSDataShape;Data "就可以了
DSConnString = "Provider=MSDataShape;Data " & ConnString
使用ADO Connection对象打开数据连接
Conn.Open DSConnString
就可以用Recordset读取层次记录集了。
查询生成记录集
打开连接之后,你还得为Recordset提供访问的查询命令字符串,为了生成上面所说的结果集,你的SQL命令应该这么写:
strSQL = "shape{select * from [Bibliotheca]} as Bibliotheca" _
& " append({select ID,CID,dept from [Book]} as Book relate ID To CID) as Book" _
& " ,Count(Book.ID) as BookCount"
接下来就可以读取Recordset了,然后Response查询结果表
rst.Open strSQL,Conn
Set rstBook = rst("Book")
Do While Not rst.Eof
Response.Write rst("Name") & " "
Do While Not rstBook.Eof
Response.Write rstBook("dept") & ","
rstBook.MoveNext
Loop
Response.Write " " & rst("BookCount") & "<br>"
Loop
需要说明的是查询语句的写法,MSDataShape的SQL查询有三个关键词:shape、append、relate。
shape{select * from [Bibliotheca]} as bibliotheca
append({select ID,CID,dept from [Book]} as Book relate ID To CID) as Book,
Count(Book.ID) as BookCount
shape之后{}中的查询语句是父表的查询,然后使用as将其命名为bibliotheca。append表是往Recordset添加字段,字段的数据在之后的()中,()内的{}中是子表的查询,用as将其命名为Book,relate之后表示父表的ID和子表的CID存在对应关系,as表示子查询为父表的字段Book,还可以用聚合函数来计算Book Count。
2003/12