如何使用SqlBulkCopy保持行顺序?

时间:2008-10-10 00:28:56

标签: sql-server excel import export sqlbulkcopy

我正在使用SqlBulkCopy以编程方式将数据从Excel导出到SQL Server 2005。它工作得很好,我唯一的问题是它不保留我在Excel文件中的行序列。我没有要排序的列,我只想按照它们在Excel电子表格中显示的顺序插入记录。

我无法修改Excel文件,必须使用我所拥有的。按任何现有列排序都会破坏序列。

请帮忙。

P.S。结束将ID列插入电子表格,看起来在导出/导入期间无法保留订单

4 个答案:

答案 0 :(得分:3)

除非您使用“ORDER BY”子句,否则我认为SQL不会指定或保证行排序。

来自Bill Vaughn的帖子(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

答案 1 :(得分:1)

经过大量研究后,似乎很明显,无法使用Microsoft编写的Bulk Insert命令保留行顺序。您必须自己直接将ID列添加到导入文件中,使用shell或其他外部脚本,或者不使用。对于微软而言,它似乎是一个需要(且容易)添加的功能,但是经过十多年的努力,它不会发生。

然而,我需要在导入后保留导入文件中的实际记录顺序,因为如果设置列具有相同的值,则更高的记录将取代较低的记录。

所以我走了另一条路。我的约束是:

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

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

所以我遇到了XML。批量上传文件直接上传到单个XML变量中。这将保留记录的顺序,因为每个记录都添加到XML中。然后解析XML变量并将结果插入表中,同时添加标识列。

假设导入文件是标准文本文件,每个记录以换行符结束(Char(13)+ Char(10))

我的方法有两个步骤:

  1. 执行IMPORT SQL语句(使用OPENROWSET),使用XML标记封装每条记录。将结果捕获到XML变量中。

  2. 通过XML标记将变量解析为表,添加递增的[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标记替换每个换行符。

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

  3. 我使用动态sql将其写入我的程序中,因此我可以传入FileName并将ID设置为从1或0开始(如果有一个标题行)。

    我能够在大约5秒内对300K记录的文件运行它。

答案 2 :(得分:0)

如果您可以将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”,您的订单将与电子表格相同。

答案 3 :(得分:0)

您还可以在表中定义一个标识列,在数据加载期间自动递增。这样,您可以在以后再次按相同顺序记录时对其进行排序。