如何使用SqlBulkCopy保持行顺序?

我正在使用SqlBulkCopy将数据以编程方式从Excel导出到SQL Server 2005。 它工作得很好,我唯一的问题是,它不保留我在Excel文件中的行序列。 我没有要sorting的列,我只是希望插入logging的顺序与它们出现在Excel电子表格中的顺序相同。

我不能修改Excel文件,而必须使用我所得到的。 通过任何现有的列进行sorting会破坏序列。

请帮忙。

PS完成将ID列插入到电子表格中,看起来像在导出/导入过程中无法保持订单

我不认为行sorting是由SQL指定或保证,除非你使用“ORDER BY”子句。

从Bill Vaughn发布的post( http://betav.com/blog/billva/2008/08/sql_server_indexing_tips_and_t.html ):

使用Order By:即使一个表有一个聚集索引(按照物理顺序存储数据),SQL Server也不保证以该(或任何特定)顺序返回行,除非使用ORDER BY子句。

与信息的另一个链接:

http://sqlblogcasts.com/blogs/simons/archive/2007/08/21/What-is-the-position-of-a-row–.aspx

经过大量研究,似乎很明显,由于Microsoft提供了大量插入命令,所以无法保留行顺序。 您必须自己直接将ID列添加到导入文件中,使用shell或其他外部脚本,否则您不需要。 看来这将是微软需要添加的function,但是经过十多年没有任何进展,这一切都不会发生。

然而,我需要在导入文件中保存实际的logging顺序,因为如果设置的列具有相同的值,较高的logging将取代那些较低的logging。

所以我走了一条不同的路线。 我的约束是:

  • 我根本无法改变源文件。 (并开创了一个不好的先例!)
  • 我无法使用外部脚本。 太复杂。 它必须是一个简单的基于T-SQL的解决scheme,不需要执行CMD。 这需要进入一个单一的程序,所以可以自动化。

我喜欢使用Powershell的逻辑来为每一行创build有序的插入语句,然后在Sql中运行。 它本质上是为每个插入队列而不是BULK插入队列。 是的,它会工作,但也会很慢。 我经常有500K +行的文件。 我需要快速的东西。

所以我碰到了XML。 将文件直接批量上传到单个XMLvariables中。 这将保留每个添加到XML的logging的顺序。 然后parsingXMLvariables并将结果插入到表中,同时添加标识列。

假定导入文件是标准文本文件,每条logging以换行符(Char(13)+ Char(10))结尾

我的方法有两个步骤:

  1. 执行IMPORT SQL语句(使用OPENROWSET),用XML标签封装每个logging。 将结果捕获到一个XMLvariables中。

  2. 通过XML标签将variablesparsing到表中,添加一个递增的[ID]列。

    --------------------------------- Declare @X xml; --------------------------------- SELECT @X=Cast('<X>'+Replace([BulkColumn],Char(13)+Char(10),'</X><X>')+'</X>' as XML) FROM OPENROWSET (BULK N'\\FileServer\ImportFolder\ImportFile_20170120.csv',SINGLE_CLOB) T --------------------------------- SELECT [Record].[X].query('.').value('.','varchar(max)') [Record] ,ROW_NUMBER() OVER (ORDER BY (SELECT 100)) [ID] --Into #TEMP FROM @X.nodes('X') [Record](X); --------------------------------- 
    • XML标签replace了每个换行符。

    • 如果文件以换行符结束,则会在最后添加空白行。 只需删除最后一行。

我使用dynamicsql将它写入我的过程中,所以我可以传入FileName并将ID设置为从1或0开始(如果有标题行)。

我能够在大约5秒钟内对300Klogging的文件执行此操作。

您也可以在数据加载期间在表中定义自动增量的标识列。 这样,您可以稍后再按照相同顺序再次对logging进行sorting。

如果您可以将Excel电子表格保存为CSV,那么使用任何脚本语言生成INSERT语句列表非常简单,该语言将按照与电子表格完全相同的顺序执行。 下面是Groovy的一个简单例子,但是任何脚本语言都可以轻松地完成这个任务:

 def file1 = new File('c:\\temp\\yourSpreadsheet.csv') def file2 = new File('c:\\temp\\yourInsertScript.sql') def reader = new FileReader(file1) def writer = new FileWriter(file2) reader.transformLine(writer) { line -> fields = line.split(',') text = """INSERT INTO table1 (col1, col2, col3) VALUES ('${fields[0]}', '${fields[1]}', '${fields[2]}');""" } 

然后,您可以对数据库执行“yourInsertScript.sql”,您的订单将与电子表格相同。