2010-04-08 76 views
5

我正尝试使用BULK INSERT从平面文件中加载SQL Server中的大量数据。然而,我的文件有不同数量的列,例如第一行包含14,第二行包含4。这是好的,我只想制作一个最大列数的表,并将文件加载到它的NULL值为缺少列。从那一点我可以玩。但是,似乎SQL Server在到达行尾并且有更多列填充目标表中的同一行时,会转移到下一行,并尝试将该行上的数据放到错误的列中桌子。批量插入的列数不一致

有没有一种方法来获得我正在寻找的行为?有没有我可以用来指定的选项?有没有人遇到过这个?

下面是代码

BULK INSERT #t 
FROM '<path to file>' 
WITH 
(
    DATAFILETYPE = 'char', 
    KEEPNULLS, 
    FIELDTERMINATOR = '#' 
) 

回答

3

BULK INSERT不是特别灵活。一种解决方法是将每行数据加载到包含单个大型varchar列的临时表中。一旦加载,你就可以用你自己的例程来解析每一行。

0

尝试用你的字段终止沿指定行终止。

BULK INSERT #t 
FROM '<path to file>' 
WITH 
( 
    DATAFILETYPE = 'char', 
    KEEPNULLS, 
    FIELDTERMINATOR = '#', 
    ROWTERMINATOR = '\n' --Or whatever signifies the end of a row in your flatfile. 
) 

这个更多信息可以在这里找到:

http://msdn.microsoft.com/en-us/library/ms191485.aspx

+1

根本不会有不同的列数工作 – gbn 2010-04-10 08:49:33

1

的不同列数意味着它不能被批量插入的代码进行解析。 它如何知道正确的列数?如果你供应太多,会怎么样?

你必须将它上传到一个有4列的表格中,并在稍后(或一个大的列)分割出其余的(或一个大列) 或预处理它以生成相同数量的列。

2

另一个解决方法是预处理文件。编写一个小的独立程序来为每行添加终止符可能更容易,因此它可以正确装载BULK,而不是使用T-SQL解析行。

下面是VB6/VBA中的一个示例。这当然不像SQL Server批量插入那么快,但它只是在10秒内预处理了91000行。

Sub ColumnDelimiterPad(FileName As String, OutputFileName As String, ColumnCount As Long, ColumnDelimiter As String, RowDelimiter As String) 
    Dim FileNum As Long 
    Dim FileData As String 

    FileNum = FreeFile() 
    Open FileName For Binary Access Read Shared As #FileNum 
    FileData = Space$(LOF(FileNum)) 
    Debug.Print "Reading File " & FileName & "..." 
    Get #FileNum, , FileData 
    Close #FileNum 

    Dim Patt As VBScript_RegExp_55.RegExp 
    Dim Matches As VBScript_RegExp_55.MatchCollection 

    Set Patt = New VBScript_RegExp_55.RegExp 
    Patt.IgnoreCase = True 
    Patt.Global = True 
    Patt.MultiLine = True 
    Patt.Pattern = "[^" & RowDelimiter & "]+" 
    Debug.Print "Parsing..." 
    Set Matches = Patt.Execute(FileData) 

    Dim FileLines() As String 
    Dim Pos As Long 
    Dim MissingDelimiters 

    ReDim FileLines(Matches.Count - 1) 
    For Pos = 0 To Matches.Count - 1 
     If (Pos + 1) Mod 10000 = 0 Then Debug.Print Pos + 1 
     FileLines(Pos) = Matches(Pos).Value 
     MissingDelimiters = ColumnCount - 1 - Len(FileLines(Pos)) + Len(Replace(FileLines(Pos), ColumnDelimiter, "")) 
     If MissingDelimiters > 0 Then FileLines(Pos) = FileLines(Pos) & String(MissingDelimiters, ColumnDelimiter) 
    Next 
    If (Pos + 1) Mod 10000 <> 0 Then Debug.Print Pos + 1 

    If Dir(OutputFileName) <> "" Then Kill OutputFileName 
    Open OutputFileName For Binary Access Write Lock Read Write As #FileNum 
    Debug.Print "Writing " & OutputFileName & "..." 
    Put #FileNum, , Join(FileLines, RowDelimiter) 
    Close #FileNum 
    Debug.Print "Done." 
End Sub 
2

我的解决方法(在T-SQL测试):

  1. 创建科拉姆数=导入文件的最小列数表
  2. 运行BULK INSERT(现在它将成功)

在上表列,你会发现所有其他项目(包括您的项目分离器)

如果您需要,请创建另一个完整列表,从第一个表中复制所有列,并仅对最后一列进行一些解析。

示例文件

alpha , beta , gamma 
one , two , three , four 

看起来像这样在你的表:

c1  | c2  | c3 
"alpha" | "beta" | "gamma" 
"one" | "two" | "three , four"