65.9K
CodeProject 正在变化。 阅读更多。
Home

使用SQLXML覆盖Schema.ini并进行批量上传

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.25/5 (5投票s)

2007年3月12日

CPOL

4分钟阅读

viewsIcon

66923

downloadIcon

341

使用SQLXML覆盖Schema.ini并进行批量上传

引言

本文介绍如何动态覆盖Schema.ini文件以方便批量上传,以及如何使用SQLXML功能将数据批量上传到SqlServer 2000表中。

背景

你的web应用程序在使用excel进行批量上传时,是否遇到过Jet引擎没有将列值视为文本的问题?

在本文中,我们将学习如何克服这个问题,并查看一个将批量数据上传到SQL Server 2000表的示例代码,使用SQLXML功能(尽管还有数百种不同的方法可以做到这一点!)。

使用代码

我每两周会收到一个很大的文件,需要上传到SQL Server表中。这些列的值带有前导零。

包含示例数据的文件看起来像这样

// sample Provider_file.txt
provider ID,License
0000018, 079376
0000019, 076185
0000021, 034733
0000024, 032921
0000025, 034551
0000043, 079331
0000107, 035911
0000272, 075555
0000295, 074591
0000331, 057518
0000342, 074673
0000371, 079491

现在,我可以使用OPENROWSET功能或DTS将此文件上传到目标表。但是,我的web应用程序中有一个小的文件上传界面,我用它来上传文件。这也使我的客户能够随时在线上传数据。

我在代码中所做的是使用日期时间戳保存此文件,以确保我不覆盖以前的文件。

<label>UploadFile</label>
<INPUT id=txtFileToUpload type=file name=txtFileToUpload 

runat="server" /> 
&nbsp;&nbsp; 
<INPUT id=btnUpLoad onclick=doProcess(); 
       type=button value=Process name=btnUpLoad 
       Runat="server" />     

然后将文件内容读取到数据集。

Dim cnn As OleDb.OleDbConnection

Dim dsCSV As New DataSet("Providers") cnn = 
    New OleDb.OleDbConnection("Provider= Microsoft.Jet.OLEDB.4.0;Data

Source=" + filePath + ";Extended Properties=Text")
Dim mySelect As String = String.Empty

mySelect = "Select * from [" & fileName & "]"

Dim da As New OleDb.OleDbDataAdapter(mySelect, cnn)
da.Fill(dsCSV)

现在,在将数据选择到数据集时,我发现包含带有前导零的数据的列没有被视为文本列类型,即使在excel中将列类型更改为文本,然后将文件转换为CSV文件也是如此。这显然意味着当数据读取到数据集时,前导零将会消失。然后我发现,为了让Jet引擎知道数据列的数据类型,我需要将包含列数据类型的Schema.ini文件放到包含数据文件的文件夹中。否则,Jet引擎会根据数据的前几行将列解释为数字。

Schema.ini覆盖

[PROVIDER_FILE_02232007090418.txt]
ColNameHeader = True
Format = CSVDelimited
CharacterSet=ANSI
Col1=IfProv Char Width 20
Col2=License Char Width 20

Schema.ini文件的第1行包含需要应用模式的目标文件名,包括文件扩展名。第2行说明目标文件中是否存在列标题。第3行包含目标文件的格式。第4行包含字符集。第4行之后,您可以开始声明列名及其数据类型。请注意,Schema.ini文件应与您尝试创建的目标数据文件位于同一文件夹中。

在我的应用程序中,由于上传是每两周进行一次,并且由于我需要保留以前上传的文件,因此我必须想出一个方法来更改Schema.ini文件中文件名(第1行)。所以我决定每次上传时都动态创建Schema.ini文件,方法是输入第一行。这段代码看起来像这样

fileStream = New FileStream(fileName, 

FileMode.Truncate)
writer = New StreamWriter(fileStream)
writer.WriteLine("[" & UploadfileName & "]")
writer.WriteLine("ColNameHeader = True")
writer.WriteLine("Format = CSVDelimited")
writer.WriteLine("CharacterSet=ANSI")
writer.WriteLine("Col1=IfProv Char Width 20")
writer.WriteLine("Col2=License Char Width 20")

将数据读取到数据集后,在获取XML输出之前重命名表和列名(如果需要)。

If Not dsCSV Is Nothing Then
   dsCSV.Tables(0).TableName = "Provider"
dsCSV.Tables(0).Columns(0).ColumnName = "IfProv"
   dsCSV.Tables(0).Columns(1).ColumnName = "License"
End If

重命名表名和列名后,XML数据将如下所示

<Providers>
    <Provider>
        <License>79376</License>
        <ifprov>0000018</ifprov>
    </Provider>
    <Provider>
        <License>76185</License>
        <ifprov>0000019</ifprov>
    </Provider> 
</Providers>

将XML数据发送到存储过程

将XML传递给存储过程进行处理。

SqlHelper.ExecuteNonQuery(ConnectionString, _
        CommandType.StoredProcedure, _
        "BULK_UPLOAD_XML_DATA", _
        New SqlParameter() { _
        New SqlParameter("@PROVDATA", xmlProviderData), 

returnParameter _
            })

使用SQLXML上传数据

创建一个包含两列的表,如下所示。

CREATE TABLE TBL_PROVIDER(IfProv VARCHAR(20) 

NULL,License VARCHAR(20) NULL)

使用SQLXML功能将XML数据上传到表的存储过程如下所示

CREATE PROC BULK_UPLOAD_PROVIDER_DATA
@PROVDATA 

    NTEXT 
AS 
    /*PARSE XML AND KEEP IT READY FOR CONSUMPTION IN THE MEMORY */ 
    EXEC SP_XML_PREPAREDOCUMENT @IDOC OUTPUT,@PROVDATA 
    
    --DUMP DATA INTO THE TBL_PROVIDER 
    INSERT INTO 
        TBL_PROVIDER (IfProv,License)
        SELECT * FROM OPENXML
              (@IDOC, '/Providers/Provider')  WITH (IfProv
                    VARCHAR(10)   'IfProv', License
        VARCHAR(10) 'License') WHERE IfProv IS NOT NULL AND License IS NOT _ 
            NULL 
        
    /*REMOVE THE DOCUMENT FROM THE    MEMORY */ 
    
    EXEC SP_XML_REMOVEDOCUMENT @IDOC

总结

我一直很喜欢使用SQL Server的SQLXML功能,我希望本文中的Schema.ini覆盖以及SQLXML功能能够帮助很多人解决他们日常的批量上传问题。

免责声明:源代码包含Microsoft的SQLHelper辅助类,用于进行数据库调用,我在我的大多数应用程序中都使用它(我相信许多读者也使用它!),它不是我编写的。我将其包含在源代码zip文件中,只是为了确保代码下载后可以正常工作。

© . All rights reserved.