Sql-Server

當每個季度的列不一致時,使用 SSIS 將 csv 文件導入 SQL Server 時出現問題

  • May 30, 2016

我正在使用 SSIS 將一堆 csv 表上傳到 SQL Server Express。csv 文件是季度數據文件。它們在很大程度上是一致的,但每隔幾年可能會添加一列或刪除現有的列。

每次 SSIS 在出現的列中遇到更改時,它都會引發以下一個或兩個錯誤:

錯誤:數據流任務中的 0xC0202055,平面文件源

$$ 2 $$: 未找到列“XYZ”的列分隔符。 錯誤:數據流任務中的 0xC0202091,平面文件源

$$ 2 $$: 跳過數據行時出錯。

添加新列時,會出現兩個錯誤。排除現有列時,僅出現 2091 錯誤。請注意,這些列在被刪除時不僅為空,它們不再存在於數據中。

是否有設置或我可以使用的東西,以便 SSIS 適應列中的這些更改?我嘗試使用完整的列集設置目標表,但這沒有幫助。

謝謝,

您可以使用腳本轉換來創建實際的列映射。對於您的平面文件源,使每個輸出行都成為一個大列。

在您的腳本轉換中,為您需要映射/已經知道的每一列創建列定義。

這假設您的第一行包含標題:

然後,在您的腳本轉換中,按您需要的分隔符分割每一行。您可以創建一個布爾值來指示第一行是否已被讀取。如果不是,則解析該行並將列映射位置儲存在 Dictionary<string,int> 中,例如 ColumnMappings,並且不要寫入 OutputBuffer。如果您的行閱讀器看到列映射已被讀取,那麼您可以將輸出設置為正確的列,例如:

OutputBuffer.MyMappedColumn = SplitRow[ColumnMappings["MyMappedColumn"]];

下面是帶有“Day”列的整個轉換的範例

using System;
using System.Data;
using System.Text;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Runtime.Wrapper;

[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public class ScriptMain : UserComponent {
   UTF8Encoding enc = new UTF8Encoding();
   char[] separator = { ',' };
   bool _isColumnMappingComplete = false;
   System.Collections.Generic.Dictionary&lt;string, int&gt; _columnMapping;
   bool isWritable = false;

   bool isColumnMappingComplete { //Set true after first row processed
       get{ return _isColumnMappingComplete; }
       set{ _isColumnMappingComplete = value;}   }

   System.Collections.Generic.Dictionary&lt;string, int&gt; columnMapping{ //Object to hold column mapping indexes
       get {
           if (_columnMapping == null) { _columnMapping = new System.Collections.Generic.Dictionary&lt;string, int&gt;(); }
           return _columnMapping; }
       set {
           _columnMapping = value;
           isColumnMappingComplete = true; } }

   public override void PreExecute() {
       base.PreExecute(); /* Add your code here for preprocessing or remove if not needed */ }

   public override void PostExecute()    {
       isWritable = true;
       base.PostExecute();
       /* Add your code here for postprocessing or remove if not needed
         You can set read/write variables here, for example: Variables.MyIntVar = 100 */  }

   public override void Input0_ProcessInputRow(Input0Buffer Row)    {
       bool isEmptyRow = false;
       //byte[] rawRowBytes = Row.Column0.GetBlobData(0,(int)Row.Column0.Length); //uncomment if using Text input datatype
       //string rawRow = enc.GetString(rawRowBytes); //uncomment if using Text input datatype
       string rawRow = Row.Column0; //comment out if using Text input datatype
       if (rawRow.Replace("\"", "").Replace(",", "").Replace(" ", "").Length == 0)
       { isEmptyRow = true; }
       if (!isEmptyRow) {
           string[] rowData = rawRow.Split(separator);

           if (!isColumnMappingComplete) {
               System.Collections.Generic.Dictionary&lt;string, int&gt; firstColMap = new System.Collections.Generic.Dictionary&lt;string, int&gt;();
               for (int i = 0; i &lt; rowData.Length; i++)
               { firstColMap.Add(rowData[i], i); }
               columnMapping = firstColMap;    }
           else {
               Output0Buffer.AddRow();
               bool _rowError = false;
               //Day
               if (columnMapping.ContainsKey("Day"))
               { Output0Buffer.Day = rowData[columnMapping["Day"]]; }
               else
               { //Output0Buffer.Day = "-";
                   _rowError = true; }   }      }    }

   public override void CreateNewOutputRows()
   {   /* Add rows by calling the AddRow method on the member variable named "&lt;Output Name&gt;Buffer".
        * For example, call MyOutputBuffer.AddRow() if your output was named "MyOutput". */ }     }

處理 SSIS 時無法動態調整。您將需要“使它們像上次一樣一致”或更改您的載入過程。目標表可以輕鬆調整,調整 txt 或 csv 文件連接器可能會更成問題。

如果可能的話,我希望從創建報告的查詢中提取數據。從長遠來看,這將最大限度地減少您的更改。

引用自:https://dba.stackexchange.com/questions/118053