Sql-Server

SSIS 檢測順序重複

  • January 8, 2022

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;
}

我錯過了什麼

  1. 包變數的持久性和腳本組件的更新?
  2. 條件拆分錶達式行為?

我的意思是,它看起來應該對我有用,但事實並非如此。

謝謝

SSIS 變數值只能​​在管道執行OnPreExecute的階段和階段進行修改。OnPostExecute在執行期間,它們是靜態的。

您可以通過使用派生列任務向數據流添加列來驗證此行為,並@[User::lastName]在腳本任務之後使用添加變數。您會看到第一行和最後一行之間的值永遠不會改變。

因此,此程式碼段存在邏輯錯誤

(Name == @[User::lastName] && Company == @[User::lastCompany])

所以你會怎麼做?

最大的挑戰當然是你有一個 330M 的行文件。

如果我們關心順序重複,那麼您設計的腳本任務幾乎是正確的,除了嘗試分配給 SSIS 變數。相反,您需要將列添加到數據流中,以便後續的條件拆分可以做出合乎邏輯的選擇。對於正常工作,我可以將 lastName 和 lastCompany 添加到數據緩衝區。但是,鑑於您將要處理大量數據,您需要爭取獲得的每一塊記憶體。我將改為在您的腳本任務中執行比較邏輯,並簡單地發出一個布爾值,指示該行是否與前一行重複。

我會有一個腳本任務,充當文件源之後的轉換。它將作為只讀輸入列CompanyName並將在輸出中添加一個新列,稱為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”。再一次,我試著讓我的意圖變得顯而易見,這樣當我必須保持它時,我就可以讓我的大腦重新投入到比賽中。

在此處輸入圖像描述

這導致我的數據流看起來像

在此處輸入圖像描述

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