SSIS 檢測順序重複
SSIS/Sql 伺服器/Visual Studio 2019。
我有一個很大的 csv 文件,裡面有很多不確定的數據。我想做的一件事是至少嘗試辨識相同的連續行並將重複的行剔除。通過“相同”,我想檢查 2 個特定的列值 - 名稱和公司。
我有一個看起來應該可以工作的流程(鑑於這是我的第一個 SSIS 包和有限的經驗),但沒有捕捉到順序重複。我不知道這是否是因為我沒有理解條件拆分錶達式語法、腳本組件的工作方式,或者包變數更改應該何時/如何從腳本組件生效。沒有人拋出錯誤,但是文件中連續重複的行不會被發送到“拒絕”滑槽。
我創建了兩個包變數(lastName 和 lastCompany),初始化為“”。
該流程有一個平面文件源讀入,然後是一個條件拆分,其中包括表達式中的其他子句,
... && !(Name == @[User::lastName] && Company == @[User::lastCompany]) &&
這個想法是任何匹配所有子句的東西都將進入“成功”路徑,而未通過任何這些檢查的行將進入“拒絕”流程。
“成功”流程的下一件事是腳本組件,它執行一些數據規範化並(至少嘗試)更新包變數。我為模板找到了另一篇文章。
public override void PostExecute() { base.PostExecute(); // I've been trying to debug this and get some output on the VS output window but so far nothing has worked. // Trace is not showing up in DbgView, FireInformation and FireWarning didn't show up in any of the windows in VS Trace.WriteLine($"Starting: [{Variables.lastName}|{Variables.lastCompany}], Ending: [{lastName}|{lastCompany}]"); Variables.lastCompany = lastCompany; Variables.lastName = lastName; } public override void Input0_ProcessInputRow(Input0Buffer Row) { ... lastName = Row.Name; lastCompany = Row.Company; }
我錯過了什麼
- 包變數的持久性和腳本組件的更新?
- 條件拆分錶達式行為?
我的意思是,它看起來應該對我有用,但事實並非如此。
謝謝
SSIS 變數值只能在管道執行
OnPreExecute
的階段和階段進行修改。OnPostExecute
在執行期間,它們是靜態的。您可以通過使用派生列任務向數據流添加列來驗證此行為,並
@[User::lastName]
在腳本任務之後使用添加變數。您會看到第一行和最後一行之間的值永遠不會改變。因此,此程式碼段存在邏輯錯誤
(Name == @[User::lastName] && Company == @[User::lastCompany])
所以你會怎麼做?
最大的挑戰當然是你有一個 330M 的行文件。
如果我們只關心順序重複,那麼您設計的腳本任務幾乎是正確的,除了嘗試分配給 SSIS 變數。相反,您需要將列添加到數據流中,以便後續的條件拆分可以做出合乎邏輯的選擇。對於正常工作,我可以將 lastName 和 lastCompany 添加到數據緩衝區。但是,鑑於您將要處理大量數據,您需要爭取獲得的每一塊記憶體。我將改為在您的腳本任務中執行比較邏輯,並簡單地發出一個布爾值,指示該行是否與前一行重複。
我會有一個腳本任務,充當文件源之後的轉換。它將作為只讀輸入列
Company
,Name
並將在輸出中添加一個新列,稱為IsDuplicate
using System; using System.Data; using Microsoft.SqlServer.Dts.Pipeline.Wrapper; using Microsoft.SqlServer.Dts.Runtime.Wrapper; [Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute] public class ScriptMain : UserComponent { // member variables to keep track of previous row data private string lastName; private string lastCompany; public override void PreExecute() { base.PreExecute(); // initialize our variables this.lastCompany = ""; this.lastName = ""; } public override void Input0_ProcessInputRow(Input0Buffer Row) { // Encapsulate the logic from the Derived Column comparison here // // Are the two elements the same? // Do we have to worry about nulls here? Assuming not // Also assuming a case sensitive match is desired if (Row.Company == this.lastCompany && Row.Name == this.lastName) { Row.IsDuplicate = true; } else { // strictly speaking, this is not required as the default value for a bit if false but I favor explicit behaviour Row.IsDuplicate = false; } // Update the member variables to the previous row's data this.lastName = Row.Name; this.lastCompany = Row.Company; } }
現在您可以將 Conditional Split 簡化為我們列的條件
IsDuplicate
。我將任何匹配的行路由到名為“Sequential Duplicate”的輸出,我的預設路徑稱為“First or non-duplicate rows”。再一次,我試著讓我的意圖變得顯而易見,這樣當我必須保持它時,我就可以讓我的大腦重新投入到比賽中。這導致我的數據流看起來像