我正在使用SqlBulkCopy以编程方式将数据从Excel导出到SQL Server 2005。它工作得很好,我唯一的问题是它不保留我在Excel文件中的行序列。我没有要排序的列,我只想按照它们在Excel电子表格中显示的顺序插入记录。
我无法修改Excel文件,必须使用我所拥有的。按任何现有列排序都会破坏序列。
请帮忙。
P.S。结束将ID列插入电子表格,看起来在导出/导入期间无法保留订单
答案 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或其他外部脚本,或者不使用。对于微软而言,它似乎是一个需要(且容易)添加的功能,但是经过十多年的努力,它不会发生。
然而,我需要在导入后保留导入文件中的实际记录顺序,因为如果设置列具有相同的值,则更高的记录将取代较低的记录。
所以我走了另一条路。我的约束是:
我喜欢使用Powershell为每一行创建有序插入语句,然后在Sql中运行的逻辑。它基本上是为每个记录排队,而不是BULK插入。是的,它会起作用,但也会很慢。我经常有500K +行的文件。我需要快速的东西。
所以我遇到了XML。批量上传文件直接上传到单个XML变量中。这将保留记录的顺序,因为每个记录都添加到XML中。然后解析XML变量并将结果插入表中,同时添加标识列。
假设导入文件是标准文本文件,每个记录以换行符结束(Char(13)+ Char(10))
我的方法有两个步骤:
执行IMPORT SQL语句(使用OPENROWSET),使用XML标记封装每条记录。将结果捕获到XML变量中。
通过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标记替换每个换行符。
如果文件以换行符结尾,则会在结尾处添加空白行。只需删除最后一行。
我使用动态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)
您还可以在表中定义一个标识列,在数据加载期间自动递增。这样,您可以在以后再次按相同顺序记录时对其进行排序。