【问题标题】:How to keep row order with SqlBulkCopy?如何使用 SqlBulkCopy 保持行顺序?
【发布时间】:2010-09-16 10:10:47
【问题描述】:

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

我无法修改 Excel 文件,必须使用现有的文件。按任何现有列排序都会打乱顺序。

请帮忙。

附:最终将 ID 列插入电子表格,看起来在导出/导入期间无法保持顺序

【问题讨论】:

  • 鉴于 SQL 表本质上是无序的,您可以通过什么方式判断插入顺序不同 - 自增列?

标签: sql-server excel import export sqlbulkcopy


【解决方案1】:

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

摘自 Bill Vaughn (http://betav.com/blog/billva/2008/08/sql_server_indexing_tips_and_t.html) 的帖子:

使用排序方式:即使表有 聚集索引(存储 数据按物理顺序),SQL Server 不保证行将是 在那个(或任何特定的)返回 order 除非 ORDER BY 子句是 用过。

另一个信息链接:

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

【讨论】:

    【解决方案2】:

    经过大量研究,显然无法使用 Microsoft 提供的 Bulk Insert 命令来保留行顺序。您必须自己将 ID 列直接添加到导入文件中,使用 shell 或其他外部脚本,或者不这样做。这似乎是微软需要(而且很容易)添加的功能,但在他们十多年没有任何东西之后,它不会发生。

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

    所以我走了一条不同的路。我的限制是:

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

    我喜欢使用 Powershell 为每一行创建有序插入语句,然后在 Sql 中运行的逻辑。它本质上是将每条记录排队等待单独插入而不是批量插入。是的,它会起作用,但它也会很慢。我经常有包含 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 标记替换每个换行符。

      • 如果文件以换行结尾,这将导致在末尾添加一个空白行。只需删除最后一行。

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

    我能够在大约 5 秒内针对 30 万条记录的文件运行此程序。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 在插入过程中订单混乱。你的方法行不通
      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-09-17
        • 2010-09-17
        • 1970-01-01
        • 2020-04-17
        • 1970-01-01
        相关资源
        最近更新 更多