2014-12-05 57 views
9

所以我一直在用BULK INSERT摔角一個令人困惑的問題一段時間。這些文件來自Linux機器,當我以十六進制編輯模式/記事本++查看它們時,它們似乎只有一個換行符(0A)作爲行終止符。我將大容量插入語句存儲在表中,稍後作業從中進行選擇並執行表中的語句以將數據加載到臨時表中。批量插入 - 用於UNIX文件的行終止符+「 l」行終止符

令我感到困惑的特例是一張有7列的表格。數據文件只有前4列,其餘應該保留NULL。

他們通常是這樣的:

BULK INSERT STAGING_TABLE FROM 'FILE_LOCATION' 
WITH  ( 
DATAFILETYPE = 'widechar' 
, FIELDTERMINATOR = ',' 
, ROWTERMINATOR = 'something_here' 
); 

該行終止一直是我的問題的最大來源。

當我嘗試使用「\ n」時,批量插入在截斷錯誤上失敗 - 它似乎將該文件視爲一個長字符串,並且只能正確劃分列,直到列用完爲止(因此截斷錯誤) 。

當我使用「0x0a」時,批量插入在「文件意外結束」錯誤時失敗。文件末尾有一個空行,但即使我刪除它仍然拋出相同的錯誤,所以我不知道那裏有什麼問題。

到目前爲止,只有一個用於將數據實際存入表中的工具是「\ l」。有誰知道這意味着什麼?我已經搜索了很多,但似乎沒有關於它的文檔。這或我一直在完全看錯了地方。

\ l作爲rowterminator的奇怪之處在於,即使它成功加載,它仍然不尊重rowterminator ...這些行只是加載到所有7列中,並在看似隨機的間隔中分割。

任何人有什麼想法?我應該澄清一些嗎?

回答

7

你遇到的問題其實不是由於行終結者。我懷疑,有文件錯誤的結束一起,你也看到類似以下的東西:

Msg 4864, Level 16, State 1, Line 1
Bulk load data conversion error (type mismatch or invalid character for the specified codepage) for row 1, column 4 ({column_name}).

雖然我說的線以下是關於ROWTERMINATOR仍然有效,真正的問題是由您的發言表示:

[the] table that has 7 columns. The data file only has the first 4 columns, the rest should be left NULL.

這是問題所在。當使用BULK INSERT時,數據文件必須具有與要插入的表相同數量的字段。如果不是這種情況,那麼您必須使用FORMATFILE ='format_file_path'選項,在這種情況下,您需要創建一個Format File並指定位置。

我想你可以逃脫更容易OPENROWSET(BULK...),這樣就可以做到以下幾點:

INSERT INTO STAGING_TABLE 
    SELECT * 
    FROM OPENROWSET(BULK 'FILE_LOCATION' ...); 

但是,這並不讓你指定一個ROWTERMINATOR不使用格式文件。因此,無論在哪種情況下都需要格式文件。

OR,你可以只導入到只有4列,然後是一個不同的臨時表:

  • 轉儲到當前STAGING_TABLE,或

  • 做一個ALTER TABLE添加3個缺失列(僅添加3個可NULL字段比將數據從一個表傳輸到另一個表更爲高效:-)。

OR,由@PhilipKelley在這個答案的評論中提到,你可以創建一個只是那些四個字段的景色,有成爲目標/目標。如果您正在執行適當的步驟以使操作被最低限度地記錄下來,則Prerequisites for Minimal Logging in Bulk Import的MSDN頁面不會以某種方式說出使用View的效果。


最有可能的\l只是解釋爲這兩個文本字符,因此它不尊重rowterminator當你嘗試過。

0x0A將工作,因爲我已測試它,它的行爲如預期。你的語句應該如下所示:

BULK INSERT STAGING_TABLE 
FROM 'FILE_LOCATION' 
WITH ( 
     DATAFILETYPE = 'widechar', 
     FIELDTERMINATOR = ',', 
     ROWTERMINATOR = '0x0A' 
); 

我既沒有在最後一行的末尾0x0A的性格和工作都一樣的嘗試。

我然後取出從線的一個逗號之一,小於全組字段離開它,那就是當我得到了以下錯誤:

Msg 4832, Level 16, State 1, Line 2 
    Bulk load: An unexpected end of file was encountered in the data file. 
Msg 7399, Level 16, State 1, Line 2 
    The OLE DB provider "BULK" for linked server "(null)" reported an error. The 
       provider did not give any information about the error. 
Msg 7330, Level 16, State 2, Line 2 
    Cannot fetch a row from OLE DB provider "BULK" for linked server "(null)". 

確保所有的數據文件中的行具有所需數量的字段分隔符(在這種情況下爲,)。你提到文件中有4列,所以每行應該是3個逗號。

+1

謝謝,您提出的替代建議最終能夠解決我的問題。這絕對是我在數據文件和登臺表之間有不同列的事實。儘管如此,我仍然對此感到困惑,因爲還有幾個其他進程按照同樣的方式構建,並且功能正確,儘管它們的列也不匹配。 在任何情況下,這一切都奏效了。謝謝! – 2014-12-11 16:40:27

+1

@RazzleDazzle很高興解決了它!關於其他類似的工作,你確定a)他們正在使用'BULK INSERT'而不是'OPENROWSET(BULK ...)'或'BCP.EXE',以及b)如果他們使用' BULK INSERT',他們還沒有使用格式文件?我沒有看到他們有可能在使用'BULK INSERT'的同時擁有不同數量的列和格式文件,除非這些列是IDENTITY或類似的東西(不能被插入)。 PS,你最終選擇哪個實際修補程序?只是好奇:) – 2014-12-11 16:46:48

+0

@RazzleDazzle只是FYI:我只是在目標表中額外的列進行測試。試圖將它作爲'DATETIME NOT NULL DEFAULT(GETDATE())'和'INT NOT NULL IDENTITY(1,1)',並且由於列數不匹配而失敗。所以不知道沒有格式化文件或使用「BULK INSERT」之外的其他進程如何工作。 – 2014-12-11 16:57:31

0

我會評論這些,但我的聲望還不夠高。

我相信「\ l」是「換行符」,這樣就會在文件編碼中看到0A。

我的第一個問題是,你的數據文件是什麼字符編碼?你的表格列上的數據類型是什麼?

我猜想這將是一個字符編碼問題。我看到你的DATAFILETYPE是'widechar'你確認你的源文件是Unicode嗎?而當您插入數據並將其選回時,它看起來好像字符編碼被保存了嗎?

+0

'\ l'只是「反斜槓l」。它不是一個解釋轉義序列。該OP在0x0A == \ n ==換行符中是正確的。但問題是源文件和目標表之間的字段號碼不匹配。 – 2014-12-08 18:17:08

0

This似乎表明使用換行符作爲行終止符'\n'將自動翻譯爲'\r\n'。它說只適用於bcp,但顯然還有其他事情正在發生。

例C在該頁面的底部說,使用了Unix行結尾的這個動態SQL:

DECLARE @bulk_cmd varchar(1000); 
SET @bulk_cmd = 'BULK INSERT AdventureWorks2012.Sales.SalesOrderDetail 
FROM ''<drive>:\<path>\<filename>'' 
WITH (ROWTERMINATOR = '''+CHAR(10)+''')'; 
EXEC(@bulk_cmd); 

這使得它看起來就像是一個已知的問題。

如果您從FTP/SFTP站點檢索文件,您可以以ASCII模式傳輸文件嗎?或者,您可以通過衆多的line ending changers(如unix2dostodos)運行該文件嗎?

我知道SSIS允許你爲行終止符指定換行符,就像導入/導出嚮導一樣。如果這是一個選項,你可以看看。您必須非常精確地在數據文件中定義列,並且對於列數很多的文件非常繁瑣,但是您通常會獲得更多選項,例如引用字段標識符等。

而且我不知道什麼控制字符\l代表。它似乎沒有記錄在任何地方。

+0

我絕對同意使用FTP/SFTP/FTPS來指定ASCII模式並讓它進行轉換。不幸的是,單靠這一點在這裏沒有幫助,因爲問題不在於行終結符:源文件和目標表的字段數目不同,但沒有指定格式文件來處理該問題。 – 2014-12-08 18:14:05