ADODataTypes与数据库值对应

The table below shows the ADO Data Type mapping between Access, SQL Server, and Oracle:

DataType EnumValueAccessSQLServerOracle
adBigInt 20   BigInt (SQL Server 2000 +)  
adBinary 128   Binary
TimeStamp
Raw *
adBoolean 11 YesNo Bit  
adChar 129   Char Char
adCurrency 6 Currency Money
SmallMoney
 
adDate 7 Date DateTime  
adDBTimeStamp 135 DateTime (Access 97 (ODBC)) DateTime
SmallDateTime
Date
adDecimal 14     Decimal *
adDouble 5 Double Float Float
adGUID 72 ReplicationID (Access 97 (OLEDB)), (Access 2000 (OLEDB)) UniqueIdentifier (SQL Server 7.0 +)  
adIDispatch 9      
adInteger 3 AutoNumber
Integer
Long
Identity (SQL Server 6.5)
Int
 
Int *
adLongVarBinary 205 OLEObject Image Long Raw *
Blob (Oracle 8.1.x)
adLongVarChar 201 Memo (Access 97)
Hyperlink (Access 97)
Text Long *
Clob (Oracle 8.1.x)
adLongVarWChar 203 Memo (Access 2000 (OLEDB))
Hyperlink (Access 2000 (OLEDB))
NText (SQL Server 7.0 +) NClob (Oracle 8.1.x)
adNumeric 131 Decimal (Access 2000 (OLEDB)) Decimal
Numeric
Decimal
Integer
Number
SmallInt
adSingle 4 Single Real  
adSmallInt 2 Integer SmallInt  
adUnsignedTinyInt 17 Byte TinyInt  
adVarBinary 204 ReplicationID (Access 97) VarBinary  
adVarChar 200 Text (Access 97) VarChar VarChar
adVariant 12   Sql_Variant (SQL Server 2000 +) VarChar2
adVarWChar 202 Text (Access 2000 (OLEDB)) NVarChar (SQL Server 7.0 +) NVarChar2
adWChar 130   NChar (SQL Server 7.0 +)  

* In Oracle 8.0.x - decimal and int are equal to number and number(10).

aspx">


CNBIE BLOG

adodb Stream 详细用法

原文:adodb Stream 详细用法
 

标题     关于Adodb.Stream 的使用说明    thinkeasy(原作)
 
关键字     Adodb.Stream
 


组件:"Adodb.Stream"
有下列方法:
Cancel 方法
     使用方法如下
     Object.Cancel
     说明:取消执行挂起的异步 Execute 或 Open 方法的调用。
Close  方法
     使用方法如下
     Object.Close
     :关闭对像
CopyTo 方法
     使用方法如下
     Object.CopyTo(destStream,[CharNumber])
     说明:将对像的数据复制,destStream指向要复制的对像,CharNumber为可选参数,指要复制的字节数,不选为全部复制。
Flush  方法
     使用方法如下
     Object.Flush
     说明:
LoadFromFile 方法
     使用方法如下
     Object.LoadFromFile(FileName)
     说明:将FileName指定的文件装入对像中,参数FileName为指定的用户名。
Open  方法
      使用方法如下
      Object.Open(Source,[Mode],[Options],[UserName],[Password])
      说明:打开对像,
      参数说明:Sourece 对像源,可不指定
  Mode 指定打开模式,可不指定,可选参数如下:
    adModeRead  =1
    adModeReadWrite =3
    adModeRecursive =4194304
    adModeShareDenyNone =16
    adModeShareDenyRead =4
    adModeShareDenyWrite =8
    adModeShareExclusive =12
    adModeUnknown  =0
    adModeWrite  =2
  Options 指定打开的选项,可不指定,可选参数如下:
    adOpenStreamAsync =1
    adOpenStreamFromRecord =4
    adOpenStreamUnspecified=-1
  UserName 指定用户名,可不指定。
  Password 指定用户名的密码
Read  方法
 使用方法如下:
 Object.Read(Numbytes)
 说明:读取指定长度的二进制内容。
 参数说明:Numbytes指定的要读取的找度,不指定则读取全部。

ReadText  方法
 使用方法如下:
 Object.ReadText(NumChars)
 说明:读取指定长度的文本
 参数说明:NumChars指定的要读取的找度,不指定则读取全部。

SaveToFile  方法
 使用方法如下:
 Object.SaveToFile(FileName,[Options])
 说明:将对像的内容写到FileName指定的文件中
 参数说明:FileName指定的文件
    Options 存取的选项,可不指定,可选参数如下:
      adSaveCreateNotExist  =1
      adSaveCreateOverWrite =2

SetEOS  方法
 使用方法如下:
 Object.setEOS()
 说明:
SkipLine  方法
 使用方法如下:
 Object.SkipLine()
 说明:
Write  方法
 使用方法如下:
 Object.Write(Buffer)
 说明:将指定的数据装入对像中。
 参数说明:Buffer 为指定的要写入的内容。
WriteText  方法
 使用方法如下:
 Object.Write(Data,[Options])
 说明:将指定的文本数据装入对像中。
 参数说明:Data 为指定的要写入的内容。
           Options 写入的选项,可不指定,可选参数如下:
    adWriteChar  =0
    adWriteLine  =1


有下列属性:
 Charset
 EOS 返回对像内数据是否为空。

 LineSeparator 指定换行格式,可选参数有
  adCR   =13
  adCRLF   =-1
  adLF   =10
 
 Mode 指定或返加模式。
 
 Position 指定或返加对像内数据的当前指针。
 
 Size 返回对像内数据的大小。
 
 State 返加对像状态是否打开。
 
 Type 指定或返回的数据类型,可选参数为:
  adTypeBinary  =1
  adTypeText  =2
 


 



CNBIE BLOG

Adodb.Command 平时很少注意到的一个参数

原文:Adodb.Command 平时很少注意到的一个参数

我们在 ASP 中调用 SQL Server 的存储过程时,如果使用 Adodb.Command 对象,通常使用如下的代码:

dim cmd, rs

set cmd = Server.CreateObject("ADODB.Command")
cmd.ActiveConnection = conn
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "TestProc"
cmd.Parameters.Append cmd.CreateParameter("@a" , adInteger, adParamInput, 4, 1)
cmd.Parameters.Append cmd.CreateParameter("@b" , adVarChar, adParamInput, 50, 'b')
...
set rs = cmd.Execute

今天我在调试一个程序的时候发现, ASP 页面上提示某个参数没有赋值, 而实际上我没赋值的却是另一个参数。 于是我打开 Sql Server 的事件探察器, 执行了一遍程序, 捕捉到实际上 ASP 发送给 Sql Server 的 SQL 语句实际上是如下的形式:

execute TestProc 1, 'b', ....

原因现在很明显了,ADO 引擎没有把对存储过程的调用翻译为完整的语法, 而是采用了上述简写方式, 这样,当中间某个参数丢失的时候, 就有可能因为错位而误判为另一个参数丢失。
然后我查了一下 Command 对象的属性, 加了如下一句:

cmd.NamedParameters = true

也就是说指定要使用显式命名的变量形式, 然后再执行一边程序, 发现事件探察器中捕捉到的语句变成了:

exec TestProc @a = 1, @b = 'b', ...

报错的参数也是正确的。
Everything is OK now



CNBIE BLOG

adodb.stream 上传问题

原文:adodb.stream 上传问题
  最近想用asp 读取各种类型的文件,包括自定于格式文件,用adodb.stream 读取,可是出现问题,在我本地调试用以下代码,没有任何问题 .但是在其他的机器上却会出现在错误行那一行提示无法读取文件,报错。各位大虾救救我,这是怎么一回事,如果是不支持adodb.stream的话,那应该在第一行就报错啊!
我也试用了无惧上传,可是直至是有限的几个格式,例如图片,文本。可一些特殊的不支持!
 Set objStream = Server.CreateObject("ADODB.Stream")
        objStream.Type = 1 ' adTypeBinary
        objStream.Open
      ' response.write strfilename
        objStream.LoadFromFile "f:/jiangai.mp3"         '错误行          '  'strFileName
        objStream.SaveToFile Server.MapPath(url),2
        objStream.Close




CNBIE BLOG

AdodbStream的方法和属性浅述

原文:AdodbStream的方法和属性浅述
 
Cancel 方法
    使用方法:Object.Cancel
    说明:取消执行挂起的异步 Execute 或 Open 方法的调用。

Close 方法
    使用方法:Object.Close
    说明:关闭对象

CopyTo 方法
    使用方法: Object.CopyTo(destStream,[CharNumber])
    说明:将对象中的数据复制,destStream指要复制的对像,CharNumber为可选参数,指要复制的字节数,不选为全部复制。

Flush 方法
    使用方法:Object.Flush
    说明:将缓存中的数据强制输出

LoadFromFile 方法
    使用方法: Object.LoadFromFile(FileName)
    说明:将FileName指定的文件装入对象中,参数FileName为指定的文件名。

Open 方法
    使用方法:Object.Open([Source],[Modem],[Options],[UserName],[Password])
    说明:打开对象
    参数说明:Sourece 对像源,可不指定
    Mode 指定打开模式,可不指定,可选参数如下:
        adModeRead=1
        adModeReadWrite=3
        adModeRecursive=4194304
        adModeShareDenyNone=16
        adModeShareDenyRead=4
        adModeShareDenyWrite=8
        adModeShareExclusive    =12
        adModeUnknown=0
        adModeWrite=2
    Options 指定打开的选项,可不指定,可选参数如下:
        adOpenStreamAsync=1
        adOpenStreamFromRecord=4
        adOpenStreamUnspecified=-1
    UserName 指定用户名,可不指定。
    Password 指定用户名的密码
    
Read 方法
    使用方法:Object.Read(Numbytes)
    说明:读取指定长度的二进制内容。
    参数说明:Numbytes指定的要读取的字节数,不指定则读取全部。

ReadText 方法
    使用方法:Object.ReadText(NumChars)
    说明:读取指定长度的文本
    参数说明:NumChars指定的要读取的字符数,不指定则读取全部。

SaveToFile 方法
    使用方法:Object.SaveToFile(FileName,[Options])
    说明:将对像的内容写到FileName指定的文件中
    参数说明:FileName指定的文件
        Options 存取的选项,可不指定,可选参数如下:
            adSaveCreateNotExist=1
            adSaveCreateOverWrite=2

SetEOS 方法
    使用方法:Object.setEOS()
    说明:将数据流设置为空
    
SkipLine 方法
    使用方法:Object.SkipLine(n)
    说明:跳过n行
    
Write 方法
    使用方法:Object.Write(Buffer)
    说明:将指定的数据装入对像中。
    参数说明:Buffer 为指定的要写入的内容。
    
WriteText 方法
    使用方法:Object.WriteText(Data,[Options])
    说明:将指定的文本数据装入对像中。
    参数说明:Data 为指定的要写入的内容。
        Options 写入的选项,可不指定,可选参数如下:
            adWriteChar=0
            adWriteLine=1

有下列属性:
    Charset:字符集
    
    EOS 返回对像内数据是否为空。
    
    LineSeparator 指定换行格式,可选参数有
        adCR=13
        adCRLF=-1
        adLF=10
    
    Mode 指定或返回模式。
    
    Position 指定或返加对像内数据的当前指针。
    
    Size 返回对像内数据的大小。
    
    State 返加对像状态是否打开。
    
    Type 指定或返回的数据类型,可选参数为:
        adTypeBinary=1
        adTypeText=2

 1<html>
 2  <body>
 3 <%
 4      Dim objet_Stream
 5      Dim Select_Fichier
 6      Dim adTypeText
 7      adTypeText = 2
 8      Select_Fichier = "c:/autoexec.bat"
 9
10      set objet_Stream = Server.CreateObject("ADODB.Stream")
11      objet_Stream.Open
12      objet_Stream.LoadFromFile Select_Fichier
13      objet_Stream.Type = adTypeText
14      Objet_Stream.Charset = "ISO-8859-1"
15
16      Taille_Fichier = objet_Stream.Size
17      Affiche_Contenu= objet_Stream.ReadText
18
19      Response.Write "Fichier : " & Select_Fichier & "<br>"
20      Response.Write "Taille : " & Taille_Fichier & " Octets<br>"
21      Response.Write "Contenu : " & Affiche_Contenu
22
23      objet_Stream.Close
24      set objet_Stream = nothing
25  %>
26  </body>
27</html>


CNBIE BLOG

ADODB入门学习

原文:ADODB入门学习
 

入门学习页面

下载地址:http://www.ifin.net.tw/adodb/adodb_tutorial_gb.htm

http://www.ifin.net.tw/adodb/adodb_tutorial_gb.htm



CNBIE BLOG

ADO编程应用(1)

原文:ADO编程应用(1)
ADO(ActiveX Data Objects)是基于组件的数据库编程接口,它是一个和编程语言无关的COM组件系统。本文主要介绍用ADO编程所需要注意的技巧和在VC下进行ADO编程的模式,并对C++ Extensions进行了简单的讨论,希望对ADO开发人员有一定的帮助作用。因为ADO是一个和编程语言无关的COM组件系统,所以这里讨论的要点适用于所有的编程语言和编程环境,比如:VBVBScript、VCJava等等。
编程技巧
1.显式定义对象类型
实际上,这条准则不仅适用于ADO编程,也适用于其他的与COM对象相关的编程。因为如果一开始就定义变量类型,则编译器在编译的时候就可以知道变量的类型,此时编译器实际上是采用vtable偏移的方式来得到具体的COM对象包含的方法的地址(这一点和C++中虚函数的地址获取方式类似);但如果一开始不指定变量类型的话,比如简单地采用如下的语句:
DIM myCon as Object
或者是:
DIM myCon
这样,编译器在编译的时候就不能得到变量的类型,而只能在运行的时候动态地得到方法的信息(通过使用接口IDispatch的Invoke方法来实现),如此为了得到方法的地址和相关的变量情况就需要在内部进行两次调用,无疑会降低程序的运行速度。
2.绑定列到具体的字段对象
程序开始时就建立对字段对象的引用,可以避免在每次得到记录后,再在Recordset::Fields中进行查找而增加系统的开销。
例如,可以采用如下所示的代码:
Private Sub TblBrowse_Click()
Dim fld1 As ADODB.Field
Dim fld2 As ADODB.Field
Dim rs As ADODB.Recordset
set rs=g_cn.execute(...)
'g_cn为全局对象adodb.connection
Set fld1 = rs.Fields(“id”) '数据表的字段
Set fld2 = rs.Fields(“name”) ’数据表的字段
If rs.BOF = False Then
While rs.BOF = False
Debug.Print fld1.Value
Debug.Print fld2.Value
rs.MoveNext
Wend
End If
rs.Close
End Sub
3.用SQL语句和存储过程进行数据更新
尽管采用Recordset对象来更新数据是非常方便的,但是它的开销也大,通过数据源对象返回的查询集不仅包含了数据,而且也包含了元数据(metadata),在有些时候元数据可能比数据本身还要大,所以最好采用SQL语句来更新数据。还有要使用存储过程而不是单一的SQL语句来获取信息。因为存储过程是在服务器端执行的,只把结果返回到客户端,这样一方面可以降低网络进行数据交互的开销,另一方面使系统更加容易维护,并且能保持数据的一致性。
4.使用集合操作单条的SELECT语句
在使用游标时,最好使用集合的方法对单条的SELECT语句进行操作。Recordset::get_Collect方法和Recordset::put_Collect方法是Recordset 对象的快捷方式,可以快速地得到一个字段的值而不需要获得关于一个字段的引用。例如,可以采用如下代码:
Sub Collect()
Dim rs As New Recordset
rs.ActiveConnection = “...”
rs.Source=“一条SQL查询语句”
rs.Open
Debug.Print rs.Collect(0),rs.Collect(1),rs.Collect(2)
Debug.Print rs!au_id, rs!au_fname, rs!au_lname
End Sub
5.只查询所需要的数据
尽管很多开发人员都习惯采用“SELECT * FROM TBL”的模式进行查询,但是为了提高系统的效率,如果只需要其中某几个字段的值,最好把这几个字段直接写出来,同时需要限定返回记录集的范围(通过WHERE子句进行限定)。
6.正确选择游标的位置、类型和锁方式
如果只需要按顺序读取记录并且不需要滚动和更新记录,最好使用服务器端游标(adUseServer)、仅向前游标(adOpenForwardOnly)和读加锁(adLockReadOnly),这样可以获得最好的性能。如果需要滚动记录,采用客户端游标(adUseServer)会比采用服务器端游标所得到的性能要好,因为ADO系统默认是采用服务器端游标类型。当然如果数据集合相当大,采用服务器端游标的性能会好一些。同时需要注意:如果采用客户端游标,最好只采用读加锁(adLockReadOnly)的锁类型,因为如果需要更新数据,客户端游标引擎需要得到额外的信息(元数据),而获取这个信息的代价是非常昂贵的。
7.调整记录集对象的CacheSize属性
ADO使用记录集对象的CacheSize属性来决定提取和缓存的记录的数目,当在缓存的范围内浏览数据时,ADO就只从缓存中提取数据。当要浏览的数据超出缓存范围的时候,ADO就释放当前缓存,提取下一些记录(提取的数目为CacheSize所指定的大小),所以必须根据具体的应用程序的情况,来设定CacheSize的大小,保证得到最佳的性能。
8.定义Command对象的参数
在许多数据源中,得到参数信息和执行命令的代价几乎是一样的,所以最好自己在程序中定义好Command参数(也就是说要定义好参数的名称、类型和方向信息),避免一些从数据提供者(Provider)那里获取信息的操作。
9.使用原始的OLE DB提供者
MDAC对许多数据源提供了原始的数据提供者,比如SQL Server、Oracle和Access数据库,这样就不需要再通过ODBC来获取数据(也就是说不需要再通过ODBC驱动这一层),这样的好处是能更快地得到数据,并且能降低磁盘和内存的开销。
10.断开Connection连接
如果使用客户端游标,就要断开Connection连接。ADO有一个特征是当使用客户端游标操作Recordset记录集的时候,不需要和服务器保持联系。所以可以充分利用这个特性降低服务器端的开销(服务器就不需要维护这些连接了)。当操作完记录集需要更新时,可以重新和数据库进行连接来更新数据。为了创建一个可以断开连接的记录集,同时需要使用静态游标(adOpenStatic)和批处理的加锁模式(adLockBatchOptimistic)。下面是有关处理的VC代码:
pRs.CreateInstance(__uuid(Recordset));
pRs->CursorLoction=adUseClient;
pRs->Open(strCmdText,strConnection,adOpenStatic,adLockBatchOptimistic,adCmdText);
pRs->PutRefActiveConnection(NULL);
//对记录集对象pRs进行操作
//重新和数据库建立连接
pRs->PutRefActiveConnectio(pCon);
//批量更新数据
pRs->UpdateBatch(adAffectAll);
需要注意的是:当执行批量更新时,必须自己处理数据冲突问题,因为更新数据时,其他用户也可能同时正在对该数据进行操作。
11.使用adExecuteNoRecords选项
如果不需要返回记录,要使用adExecuteNoRecords选项。ADO 2.0包括一个新的执行选项称为adExecuteNoRecords。当使用该选项的时候,ADO就不会创建记录集对象,不设置任何游标属性。数据提供者因为不需要认证集合的属性而使性能得到优化。具体的例子如下:
con.Execute “insert into tbl values(fv1, fv2) ”, , adExecuteNoRecords
对仅有一条的执行语句采用Connection::Execute方法比使用Recordset::Open方法或者是Command::Execute方法的效果要好,因为ADO不保留任何命令状态的信息,因此执行性能就有所改进。
12.使用session/connection缓冲池
因为数据库的打开和关闭非常消耗系统资源,因此,使用连接池对基于多层的应用的性能会有很大的提高。当使用MDAC的时候,开发人员本身并不需要考虑对数据库连接的缓存,MDAC会自动处理它。连接池在两个层次上提供支持:OLE DB sessions和ODBC连接。如果使用ADO,数据库连接会自动被OLE DB session缓冲池所缓存;如果使用ODBC,可以利用在ODBC数据源管理中新的连接缓冲池选项对ODBC缓冲进行设置。
实现方法
我们知道,在VB下进行基于ADO的编程相对比较简单,只要通过reference加载了适当的类型库后,就可以正常地调用ADO对象。但是对于VC下的基于ADO的数据库开发就稍微复杂一些。VC中实现对ADO操作通常有三种方法:
●#import方法;
●利用MFC OLE的ClassWizard;
●通过Windows API中COM相关的函数。
在这三种方法中,#import是最方便的方法,它允许产生一个类似VB的类结构,使程序开发变得很方便。下面分别介绍这三种方法。
1.#import方法
在#import方法中,需要提供所要包含的类型库的路径和名称,VC能够自动产生一个对GUIDs的定义,以及自动生成对ADO对象的封装。对任何引用的类型库,VC会在编译的时候自动生成两个文件:
●头文件(.tlh):包含了所列举的类型和对类型库中对象的定义;
●实现文件(.tli):对类型库对象模型中的方法产生封装。
例如,在stdafx.h文件中增加对msado15.dd的#import之后,VC会产生msado15.tlh和msado15.tli两个文件。
#import能够使用一个新的类_com_ptr_t,它也被称为智能指针。智能指针能够自动执行QuyerInterface、AddRef和Release函数。
下面的代码演示了如何使用#import在应用中实现对ADO的操作:
#import “c:/program files/common files/system/ado/msado15.dll” /no_namespace
rename ( “EOF”, “adoEOF” )
重命名EOF是必要的,因为典型的VC应用都已经定义了EOF作为常数-1。
通常来说,操作一个自动化对象需要定义和初始化一个用来操作的变量。可以通过使用智能指针
(_com_ptr_t)的构造函数传递一个有效的CLSID或者是PROGID,也可以通过_com_ptr_t::CreateInstance()方法来定义对象。具体代码如下所示:
_ConnectionPtr Conn1( __uuidof( Connection ) );
也可以采用下面的代码实现同样的功能:
_ConnectionPtr Conn1 = NULL; //定义对象
HRESULT hr = S_OK;
//创建实例
hr =Conn1.CreateInstance( __uuidof( Connection ) );
推荐采用第二种方式,因为用第一种方式不能返回一个失败的HRESULT,所以也就不能判断ADO连接对象是成功还是失败,以及失败的原因。注意这里的__uuidof( Connection)中的Connection是在.tlh文件中定义的。通过把它传递给方法CreateInstance,就可以创建一个有效的ADOConnection对象。
需要注意的是#import的no_namespace属性,它告诉编译器该类在不在一个单独的名字空间中。使用no_namespace意味着不需要在初始化变量时引用名字空间。当然如果在应用中需要导入多个类型库时,最好不要使用no_namespace,以免引起名字冲突。


CNBIE BLOG

ADO存取数据库时的分页显示详

原文:ADO存取数据库时的分页显示详
 
什么是 ADO 存取数据库时的分页显示?如果你使用过目前众多网站上的电

子公告板程序的话,那你应该会知道电子公告板程序为了提高页面的读取速度,

一般不会将所有的帖子全部在一页中罗列出来,而是将其分成多页显示,每页
显示一定数目的帖子数,譬如 20 条。想不想了解如何实现分页显示?请看
本文!
  那么究竟如何才能做到将数据库的查询结果分页显示呢?其实方法有很多,

但主要有两种:
  一、将数据库中所有符合查询条件的记录一次性的都读入 recordset 中,

存放在内存中,然后通过 ADO Recordset 对象所提供的几个专门支持分页处
理的属性: PageSize( 页大小 )、 PageCount( 页数目 ) 以及
AbsolutePage( 绝对页 ) 来管理分页处理。
  二、根据客户的指示,每次分别从符合查询条件的记录中将规定数目的记
录数读取出来并显示。
  两者的主要差别在于前者是一次性将所有记录都读入内存然后再根据指示
来依次做判断分析从而达到分页显示的效果,而后者是先根据指示做出判断并
将规定数目的符合查询条件的记录读入内存,从而直接达到分页显示的功能。

  我们可以很明显的感觉到,当数据库中的记录数达到上万或更多时,第一
种方法的执行效率将明显低于第二种方法,因为当每一个客户查询页面时都要
将所有符合条件的记录存放在服务器内存中,然后在进行分页等处理,如果
同时有超过 100 个的客户在线查询,那么 ASP 应用程序的执行效率将大受
影响。但是,当服务器上数据库的记录数以及同时在线的人数并不是很多时,
两者在执行效率上是相差无几的,此时一般就采用第一种方法,因为第一种
方法的 ASP 程序编写相对第二种方法要简单明了得多。
  在这里作者就以我们常见的 ASP BBS 程序为例,来给大家分析一下如何
在 BBS 程序里实现分页显示功能,由于我们一般使用的 BBS 程序数据库
记录数和同时访问的人数都不会太多,所以以下程序实例是使用的先前所介绍
的第一种分页显示方法。
   进行 ADO 存取数据库时的分页显示,其实就是对 Recordset 的记录
进行操作。所以我们首先必须了解 Reordset 对象的属性和方法:
   BOF 属性:目前指标指到 RecordSet 的第一笔。
   EOF 属性:目前指标指到 RecordSet 的最后一笔。
   Move 方法:移动指标到 RecordSet 中的某一条记录。
   AbsolutePage 属性:设定当前记录的位置是位于哪一页
AbsolutePosition 属性:目前指标在 RecordSet 中的位置。
   PageCount 属性:显示 Recordset 对象包括多少“页”的数据。
   PageSize 属性:显示 Recordset 对象每一页显示的记录数。
   RecordCount 属性:显示 Recordset 对象记录的总数。
   下面让我们来详细认识一下这些重要的属性和方法
   一、 BOF 与 EOF 属性
   通常我们在 ASP 程序中编写代码来检验 BOF 与 EOF 属性,从而得知
目前指标所指向的 RecordSet 的位置,使用 BOF 与 EOF 属性,可以得知
一个 Recordset 对象是否包含有记录或者得知移动记录行是否已经超出该
Recordset 对象的范围。
   如: < % if not rs.eof then ... %>
   < % if not (rs.bof and rs.eof) %>
  若当前记录的位置是在一个 Recordset 对象第一行记录之前时, BOF
属性返回 true,反之则返回 false。
  若当前记录的位置是在一个 Recordset 对象最后一行记录之后时,
EOF 属性返回 true,反之则返回 false。
  BOF 与 EOF 都为 False:表示指标位于 RecordSet 的当中。
  BOF 为 True:目前指标指到 RecordSet 的第一笔记录。
EOF 为 True:目前指标指到 RecordSet 的最后一笔记录。
  BOF 与 EOF 都为 True:在 RecordSet 里没有任何记录。
  二、 Move 方法
  您可以用 Move 方法移动指标到 RecordSet 中的某一笔记录,语法如下:

  rs.Move NumRecords,Start
  这里的“rs”为一个对象变量,表示一个想要移动当当前记录位置的
Recordset 对象;“NumRecords”是一个正负数运算式,设定当前记录位置
的移动数目;“start”是一个可选的项目,用来指定记录起始的标签。
   所有的 Recordset 对象都支持 Move 方法,如果 NumRecords 参数
大于零,当前记录位置向末尾的方向移动;如果其小于零,则当前记录位置
向开头的方向移动;如果一个空的 Recordset 对象调用 Move 方法,将会
产生一个错误。
   MoveFirst 方法:将当前记录位置移至第一笔记录。
   MoveLast 方法:将当前记录位置移至最后一笔记录。
   MoveNext 方法:将当前记录位置移至下一笔记录。
MovePrevious 方法:将当前记录位置移至上一笔记录。
   Move [n] 方法:移动指标到第 n 笔记录, n 由 0 算起。
  三、 AbsolutePage 属性
  AbsolutePage 属性设定当前记录的位置是位于哪一页的页数编号;
使用 PageSize 属性将 Recordset 对象分割为逻辑上的页数,每一页的记录
数为 PageSize( 除了最后一页可能会有少于 PageSize 的记录数 )。这里
必须注意并不是所有的数据提供者都支持此项属性,因此使用时要小心。
  与 AbsolutePosition 属性相同, AbsolutePage 属性是以 1 为起始
的,若当前记录为 Recordset 的第一行记录, AbsolutePage 为 1。可以
设定 AbsolutePage 属性,以移动到一个指定页的第一行记录位置。
  四、 AbsolutePosition 属性
  若您需要确定目前指标在 RecordSet 中的位置,您可以用
AbsolutePosition 属性。
  AbsolutePosition 属性的数值为目前指标相对於第一笔的位置,由 1
算起,即第一笔的 AbsolutePosition 为 1。
  注意 , 在存取 RecordSet 时,无法保证 RecordSet 每次都以同样的
顺序出现。
  若要启用 AbsolutePosition,必须先设定为使用用户端
cursor( 指针 ), asp 码如下:
  rs2.CursorLocation = 3
  五、 PageCount 属性
  使用 PageCount 属性,决定 Recordset 对象包括多少“页”的数据。
这里的“页”是数据记录的集合,大小等于 PageSize 属性的设定,即使最后
一页的记录数比 PageSize 的值少,最后一页也算是 PageCount 的一页。
必须注意也并不是所有的数据提供者都支持此项属性。
  六、 PageSize 属性
  PageSize 属性是决定 ADO 存取数据库时如何分页显示的关键,使用它
就可以决定多少记录组成一个逻辑上的“一页”。设定并建立一个页的大小,
从而允许使用 AbsolutePage 属性移到其它逻辑页的第一条记录。
PageSize 属性能随时被设定。
  七、 RecordCount 属性
  这也是一个非常常用和重要的属性,我们常用 RecordCount 属性来找出
一个 Recordset 对象包括多少条记录。如:
< % totle=RS.RecordCount %>
  在了解了 Recordset 对象的以上属性和方法后,我们来考虑一下,
如何运用它们来达到我们分页显示的目的。首先,我们可以为 PageSize 属性
设置一个值,从而指定从记录组中取出的构成一个页的行数;然后通过
RecordCount 属性来确定记录的总数;再用记录总数除以 PageSize 就可得
到所显示的页面总数;最后通过 AbsolutePage 属性就能完成对指定页的访问
好象很并不复杂呀,下面让我们来看看程序该如何实现呢?
  我们建立这样一个简单的 BBS 应用程序,它的数据库中分别有以下五个
字段:“ID”,每个帖子的自动编号;“subject”,每个帖子的主题;
“name”,加帖用户的姓名;“email”,用户的电子邮件地址;
“postdate”,加帖的时间。数据库的 DSN 为“bbs”。我们将显示帖子
分页的所有步骤放在一个名为“ShowList()”的过程中,方便调用。
程序如下:

'----BBS 显示帖子分页----
< % Sub ShowList() %>
< %
PgSz=20 '设定开关,指定每一页所显示的帖子数目,默认为20帖一页
Set Conn = Server.CreateObject("ADODB.Connection")
Set RS = Server.CreateObject("ADODB.RecordSet")
sql = "SELECT * FROM message order by ID DESC"
'查询所有帖子,并按帖子的ID倒序排列
Conn.Open "bbs"
RS.open sql,Conn,1,1
If RS.RecordCount=0 then
response.write "< P>< center>对不起,数据库中没有相关信息!
< /center>< /P>"
else
RS.PageSize = Cint(PgSz) '设定PageSize属性的值
Total=INT(RS.recordcount / PgSz * -1)*-1 '计算可显示页面的总数
PageNo=Request("pageno")
if PageNo="" Then
PageNo = 1
else
PageNo=PageNo+1
PageNo=PageNo-1
end if
ScrollAction = Request("ScrollAction")
if ScrollAction = " 上一页 " Then
PageNo=PageNo-1
end if
if ScrollAction = " 下一页 " Then
PageNo=PageNo+1
end if
if PageNo < 1 Then
PageNo = 1
end if
n=1
RS.AbsolutePage = PageNo
Response.Write "< CENTER>"
position=RS.PageSize*PageNo
pagebegin=position-RS.PageSize+1
if position < RS.RecordCount then
pagend=position
else
pagend= RS.RecordCount
end if
Response.Write "< P>< font color='Navy'>< B>数据库查询结果:< /B>"
Response.Write "(共有"&RS.RecordCount &"条符合条件的信息,
显示"&pagebegin&"-"&pagend&")< /font>< /p>"
Response.Write "< TABLE WIDTH=600 BORDER=1 CELLPADDING=4
CELLSPACING=0 BGCOLOR=#FFFFFF>"
Response.Write "< TR BGCOLOR=#5FB5E2>< FONT SIZE=2>< TD>
< B>主题< /B>< /TD>< TD>< B>用户< /B>< /TD>< TD>< B>Email< /B>
< /TD>< TD>< B>发布日期< /B>< /TD>< /FONT>< TR BGCOLOR=#FFFFFF>"
Do while not (RS is nothing)
RowCount = RS.PageSize
Do While Not RS.EOF and rowcount > 0
If n=1 then
Response.Write "< TR BGCOLOR=#FFFFFF>"
ELSE
Response.Write "< TR BGCOLOR=#EEEEEE>"
End If
n=1-n %>
< TD>< span style="font-size:9pt">
< A href='view.asp?key=< % =RS("ID")%>'>< % =RS("subject")%>
< /A>< /span>< /td>
< TD>< span style="font-size:9pt">
< % =RS("name")%>< /A>< /span>< /td>
< TD>< span style="font-size:9pt">
< a href="mailto:< % =RS("email")%>">< % =RS("email")%>< /a>
< /span> < /TD>
< TD>< span style="font-size:9pt">
< % =RS("postdate")%>< /span> < /td>
< /TR>
< %
RowCount = RowCount - 1
RS.MoveNext
Loop
set RS = RS.NextRecordSet
Loop
Conn.Close
set rs = nothing
set Conn = nothing
%>
< /TABLE>
< FORM METHOD=GET ACTION="list.asp">
< INPUT TYPE="HIDDEN" NAME="pageno" VALUE="< % =PageNo %>">
< %
if PageNo > 1 Then
response.write "< INPUT TYPE=SUBMIT NAME='ScrollAction'
VALUE=' 上一页 '>"
end if
if RowCount = 0 and PageNo < >Total then
response.write "< INPUT TYPE=SUBMIT NAME='ScrollAction'
VALUE=' 下一页 '>"
end if
response.write "< /FORM>"
End if
%>
< % End Sub %>
  相信大家都应该能完全读懂上面的程序,因此就不在此详细解释了。
值得注意的是在这段程序中运用了一个小技巧 < INPUT TYPE="HIDDEN"
NAME="pageno" VALUE="< % =PageNo %>">,这是用来在每次调用该
ASP 文件时传递数据的“暗道”,由于我们需要在每次调用程序时传递代表
当前页码的参数,可能大家会想到使用 session,但是从节省系统资源和
通用性来讲,用这样一个隐藏的 form 来传递数据将会达到更好的效果。


CNBIE BLOG

ADO第一次亲密接触 -- ADO开发实践之一

原文:ADO第一次亲密接触 -- ADO开发实践之一
 

ADO第一次亲密接触 -- ADO开发实践之一
作者:浙江省温岭市电信公司 王骏


一、ADO简介
ADO(ActiveX Data Object)是Microsoft数据库应用程序开发的新接口,是建立在OLE DB之上的高层数据库访问技术,请不必为此担心,即使你对OLE DB,COM不了解也能轻松对付ADO,因为它非常简单易用,甚至比你以往所接触的ODBC API、DAO、RDO都要容易使用,并不失灵活性。本文将详细地介绍在VC下如何使用ADO来进行数据库应用程序开发,并给出示例代码。
vckbase10/src/adotest1.zip">本文示例代码

二、基本流程
万事开头难,任何一种新技术对于初学者来说最重要的还是“入门”,掌握其要点。让我们来看看ADO数据库开发的基本流程吧!
(1)初始化COM库,引入ADO库定义文件
(2)用Connection对象连接数据库
(3)利用建立好的连接,通过Connection、Command对象执行SQL命令,或利用Recordset对象取得结果记录集进行查询、处理。
(4)使用完毕后关闭连接释放对象。

准备工作:
为了大家都能测试本文提供的例子,我们采用Access数据库,您也可以直接在我们提供的示例代码中找到这个test.mdb。
下面我们将详细介绍上述步骤并给出相关代码。
【1】COM库的初始化
我们可以使用AfxOleInit()来初始化COM库,这项工作通常在CWinApp::InitInstance()的重载函数中完成,请看如下代码:

BOOL CADOTest1App::InitInstance()  {  AfxOleInit();  ...... 
【2】用#import指令引入ADO类型库
我们在stdafx.h中加入如下语句:(stdafx.h这个文件哪里可以找到?你可以在FileView中的Header Files里找到)
#import "c:/program files/common files/system/ado/msado15.dll" no_namespace rename("EOF","adoEOF")

这一语句有何作用呢?其最终作用同我们熟悉的#include类似,编译的时候系统会为我们生成msado15.tlh,ado15.tli两个C++头文件来定义ADO库。

几点说明:
(1) 您的环境中msado15.dll不一定在这个目录下,请按实际情况修改
(2) 在编译的时候肯能会出现如下警告,对此微软在MSDN中作了说明,并建议我们不要理会这个警告。
msado15.tlh(405) : warning C4146: unary minus operator applied to unsigned type, result still unsigned

【3】创建Connection对象并连接数据库
首先我们需要添加一个指向Connection对象的指针:
_ConnectionPtr m_pConnection;
下面的代码演示了如何创建Connection对象实例及如何连接数据库并进行异常捕捉。

BOOL CADOTest1Dlg::OnInitDialog()  {  CDialog::OnInitDialog();  HRESULT hr;  try  {  hr = m_pConnection.CreateInstance("ADODB.Connection");///创建Connection对象  if(SUCCEEDED(hr))  {  hr = m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=test.mdb","","",adModeUnknown);///连接数据库  ///上面一句中连接字串中的Provider是针对ACCESS2000环境的,对于ACCESS97,需要改为:Provider=Microsoft.Jet.OLEDB.3.51;
} } catch(_com_error e)///捕捉异常 { CString errormessage; errormessage.Format("连接数据库失败!/r/n错误信息:%s",e.ErrorMessage()); AfxMessageBox(errormessage);///显示错误信息 }

在这段代码中我们是通过Connection对象的Open方法来进行连接数据库的,下面是该方法的原型
HRESULT Connection15::Open ( _bstr_t ConnectionString, _bstr_t UserID, _bstr_t Password, long Options )
ConnectionString为连接字串,UserID是用户名, Password是登陆密码,Options是连接选项,用于指定Connection对象对数据的更新许可权,
Options可以是如下几个常量:
adModeUnknown:缺省。当前的许可权未设置
adModeRead:只读
adModeWrite:只写
adModeReadWrite:可以读写
adModeShareDenyRead:阻止其它Connection对象以读权限打开连接
adModeShareDenyWrite:阻止其它Connection对象以写权限打开连接
adModeShareExclusive:阻止其它Connection对象打开连接
adModeShareDenyNone:允许其它程序或对象以任何权限建立连接

我们给出一些常用的连接方式供大家参考:
(1)通过JET数据库引擎对ACCESS2000数据库的连接

m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C://test.mdb","","",adModeUnknown);

(2)通过DSN数据源对任何支持ODBC的数据库进行连接:
m_pConnection->Open("Data Source=adotest;UID=sa;PWD=;","","",adModeUnknown);

(3)不通过DSN对SQL SERVER数据库进行连接:
m_pConnection->Open("driver={SQL Server};Server=127.0.0.1;DATABASE=vckbase;UID=sa;PWD=139","","",adModeUnknown);

其中Server是SQL服务器的名称,DATABASE是库的名称

Connection对象除Open方法外还有许多方法,我们先介绍Connection对象中两个有用的属性ConnectionTimeOut与State
ConnectionTimeOut用来设置连接的超时时间,需要在Open之前调用,例如:
m_pConnection->ConnectionTimeout = 5;///设置超时时间为5秒m_pConnection->Open("Data Source=adotest;","","",adModeUnknown);


State属性指明当前Connection对象的状态,0表示关闭,1表示已经打开,我们可以通过读取这个属性来作相应的处理,例如:
if(m_pConnection->State)     m_pConnection->Close(); ///如果已经打开了连接则关闭它

【4】执行SQL命令并取得结果记录集
为了取得结果记录集,我们定义一个指向Recordset对象的指针:_RecordsetPtr m_pRecordset;
并为其创建Recordset对象的实例: m_pRecordset.CreateInstance("ADODB.Recordset");
SQL命令的执行可以采用多种形式,下面我们一进行阐述。

(1)利用Connection对象的Execute方法执行SQL命令
Execute方法的原型如下所示:
_RecordsetPtr Connection15::Execute ( _bstr_t CommandText, VARIANT * RecordsAffected, long Options ) 其中CommandText是命令字串,通常是SQL命令。参数RecordsAffected是操作完成后所影响的行数, 参数Options表示CommandText中内容的类型,Options可以取如下值之一:
adCmdText:表明CommandText是文本命令
adCmdTable:表明CommandText是一个表名
adCmdProc:表明CommandText是一个存储过程
adCmdUnknown:未知

Execute执行完后返回一个指向记录集的指针,下面我们给出具体代码并作说明。
  _variant_t RecordsAffected;  ///执行SQL命令:CREATE TABLE创建表格users,users包含四个字段:整形ID,字符串username,整形old,日期型birthday  m_pConnection->Execute("CREATE TABLE users(ID INTEGER,username TEXT,old INTEGER,birthday DATETIME)",&RecordsAffected,adCmdText);  ///往表格里面添加记录  m_pConnection->Execute("INSERT INTO users(ID,username,old,birthday) VALUES (1, ''''''''Washington'''''''',25,''''''''1970/1/1'''''''')",&RecordsAffected,adCmdText);  ///将所有记录old字段的值加一  m_pConnection->Execute("UPDATE users SET old = old+1",&RecordsAffected,adCmdText);  ///执行SQL统计命令得到包含记录条数的记录集  m_pRecordset =  m_pConnection->Execute("SELECT COUNT(*) FROM users",&RecordsAffected,adCmdText);  _variant_t vIndex = (long)0;  _variant_t vCount = m_pRecordset->GetCollect(vIndex);///取得第一个字段的值放入vCount变量  m_pRecordset->Close();///关闭记录集  CString message;  message.Format("共有%d条记录",vCount.lVal);  AfxMessageBox(message);///显示当前记录条数

(2)利用Command对象来执行SQL命令

  _CommandPtr m_pCommand;  m_pCommand.CreateInstance("ADODB.Command");  _variant_t vNULL;  vNULL.vt = VT_ERROR;  vNULL.scode = DISP_E_PARAMNOTFOUND;///定义为无参数  m_pCommand->ActiveConnection = m_pConnection;///非常关键的一句,将建立的连接赋值给它  m_pCommand->CommandText = "SELECT * FROM users";///命令字串  m_pRecordset = m_pCommand->Execute(&vNULL,&vNULL,adCmdText);///执行命令,取得记录集

在这段代码中我们只是用Command对象来执行了SELECT查询语句,Command对象在进行存储过程的调用中能真正体现它的作用。下次我们将详细介绍。

(3)直接用Recordset对象进行查询取得记录集
例如

  m_pRecordset->Open("SELECT * FROM users",_variant_t((IDispatch *)m_pConnection,true),adOpenStatic,adLockOptimistic,adCmdText);

Open方法的原型是这样的:
HRESULT Recordset15::Open ( const _variant_t & Source, const _variant_t & ActiveConnection, enum CursorTypeEnum CursorType, enum LockTypeEnum LockType, long Options )
其中:
Source是数据查询字符串
ActiveConnection是已经建立好的连接(我们需要用Connection对象指针来构造一个_variant_t对象)
CursorType光标类型,它可以是以下值之一,请看这个枚举结构:
enum CursorTypeEnum
{
adOpenUnspecified = -1,///不作特别指定
adOpenForwardOnly = 0,///前滚静态光标。这种光标只能向前浏览记录集,比如用MoveNext向前滚动,这种方式可以提高浏览速度。但诸如BookMark,RecordCount,AbsolutePosition,AbsolutePage都不能使用
adOpenKeyset = 1,///采用这种光标的记录集看不到其它用户的新增、删除操作,但对于更新原有记录的操作对你是可见的。
adOpenDynamic = 2,///动态光标。所有数据库的操作都会立即在各用户记录集上反应出来。
adOpenStatic = 3///静态光标。它为你的记录集产生一个静态备份,但其它用户的新增、删除、更新操作对你的记录集来说是不可见的。
};
LockType锁定类型,它可以是以下值之一,请看如下枚举结构:
enum LockTypeEnum
{
adLockUnspecified = -1,///未指定
adLockReadOnly = 1,///只读记录集
adLockPessimistic = 2,悲观锁定方式。数据在更新时锁定其它所有动作,这是最安全的锁定机制
adLockOptimistic = 3,乐观锁定方式。只有在你调用Update方法时才锁定记录。在此之前仍然可以做数据的更新、插入、删除等动作
adLockBatchOptimistic = 4,乐观分批更新。编辑时记录不会锁定,更改、插入及删除是在批处理模式下完成。
};
Options请参考本文中对Connection对象的Execute方法的介绍


【5】记录集的遍历、更新
根据我们刚才通过执行SQL命令建立好的users表,它包含四个字段:ID,username,old,birthday
以下的代码实现:打开记录集,遍历所有记录,删除第一条记录,添加三条记录,移动光标到第二条记录,更改其年龄,保存到数据库

_variant_t vUsername,vBirthday,vID,vOld;_RecordsetPtr m_pRecordset;m_pRecordset.CreateInstance("ADODB.Recordset");m_pRecordset->Open("SELECT * FROM users",_variant_t((IDispatch*)m_pConnection,true),adOpenStatic,adLockOptimistic,adCmdText);while(!m_pRecordset->adoEOF)///这里为什么是adoEOF而不是EOF呢?还记得rename("EOF","adoEOF")这一句吗?{vID = m_pRecordset->GetCollect(_variant_t((long)0));///取得第1列的值,从0开始计数,你也可以直接给出列的名称,如下一行vUsername = m_pRecordset->GetCollect("username");///取得username字段的值vOld = m_pRecordset->GetCollect("old");vBirthday = m_pRecordset->GetCollect("birthday");///在DEBUG方式下的OUTPUT窗口输出记录集中的记录if(vID.vt != VT_NULL && vUsername.vt != VT_NULL && vOld.vt != VT_NULL && vBirthday.vt != VT_NULL)TRACE("id:%d,姓名:%s,年龄:%d,生日:%s/r/n",vID.lVal,(LPCTSTR)(_bstr_t)vUsername,vOld.lVal,(LPCTSTR)(_bstr_t)vBirthday);m_pRecordset->MoveNext();///移到下一条记录}m_pRecordset->MoveFirst();///移到首条记录m_pRecordset->Delete(adAffectCurrent);///删除当前记录///添加三条新记录并赋值for(int i=0;i<3;i++){m_pRecordset->AddNew();///添加新记录m_pRecordset->PutCollect("ID",_variant_t((long)(i+10)));m_pRecordset->PutCollect("username",_variant_t("叶利钦"));m_pRecordset->PutCollect("old",_variant_t((long)71));m_pRecordset->PutCollect("birthday",_variant_t("1930-3-15"));}m_pRecordset->Move(1,_variant_t((long)adBookmarkFirst));///从第一条记录往下移动一条记录,即移动到第二条记录处m_pRecordset->PutCollect(_variant_t("old"),_variant_t((long)45));///修改其年龄m_pRecordset->Update();///保存到库中
【6】关闭记录集与连接
记录集或连接都可以用Close方法来关闭
      m_pRecordset->Close();///关闭记录集      m_pConnection->Close();///关闭连接
至此,我想您已经熟悉了ADO操作数据库的大致流程,也许您已经胸有成竹,也许您还有点胡涂,不要紧!建议你尝试写几个例子,这样会更好地熟悉ADO,最后我给大家写了一个小例子,例子中读出所有记录放到列表控件中、并可以添加、删除、修改记录。
vckbase10/src/adotest1.zip">点这里下载示例代码

后记:限于篇幅ADO中的许多内容还没有介绍,下次我们将详细介绍Recordset对象的属性、方法并解决几个关键的技术:绑定方式处理记录集数据、存储过程的调用、事务处理、图象在数据库中的保存与读取、与表格控件的配合使用等。
下次再见吧!


CNBIE BLOG

ADO方式下判断数据表是否存在

原文:ADO方式下判断数据表是否存在
 

 查看:[javascript:doZoom(12)">大字体 javascript:doZoom(10.5)">中字体 javascript:doZoom(9)">小字体]

前段时间做一个管理系统的时候,一个朋友问我不用数据库,用EXCEL可以做不,当时在做的过程中出了一一些的问题,就想现在说到的这样,我在判断数据是否存在的时候有一些问题,现在在网上找了点资料,整理后贴在这里.

下面构造两个可重载的函数,用于在ADO方式下判断数据库的数据表是否存在。


//函数一:

Function TableExist( pAdoCmd: TADOCOMMAND; pcTable : string ) : boolean ; overload ;
var cError : string ;
begin
ADO_COMMAND_EXEC( pAdoCmd, 'Select top 1 from ' + pcTable , cError );
result := ( cError = '' );
end ;

//函数二:
 

Function TableExist( pConn:TADOConnection; pcTable : string ) : boolean ; overload ;
var tmpFldList : TStrings ;
nLoop : integer ;
begin
Result := False ;
tmpFldList := TStringList.Create ;
pConn.GetTableNames( tmpFldList, True ); // 包含系统
for nLoop := 0 to tmpFldList.Count - 1 do
begin
if uppercase( tmpFldList[nLoop] ) = uppercase( pcTable ) then
begin
Result := True ;
break ;
end;
end;
tmpFldList.Free ;
end;
原文地址:https://www.cnblogs.com/Ruiky/p/2541303.html