【问题标题】:SSIS fails if the data exists in the database如果数据库中存在数据,则 SSIS 失败
【发布时间】:2021-01-20 10:04:35
【问题描述】:

我有一个带有索引唯一 ID 的 SQL 数据库。 我正在使用 SSIS 将数据从 Excel 导入 SQL 数据库。如果 ID 存在于数据库中,我会收到一个错误,当我的 SQL Server 数据库中有重复项时,无法在具有唯一索引的对象中插入重复的键行,我想要的是 SSIS 跳过导入此行,如果数据库中存在该行(它的 ID),则跳转到下一个。我该如何解决这个问题?

【问题讨论】:

  • “我该如何解决这个问题?” 不要插入重复的值。
  • 您可以将目标的错误输出修改为“重定向”或“忽略”而不是“失败组件”,也可以将查找添加到您的数据流中,将其修改为“重定向到输出”以及您在目的地使用“不匹配”输出的位置。

标签: sql-server ssis ssis-2012


【解决方案1】:

你可以使用:

  1. 使用条件拆分转换的聚合转换

将聚合转换带到数据流窗格并将您的 Excel 文件源连接到聚合转换。您需要将它们分组并计数。

将条件拆分转换拖动到数据流窗格并将聚合转换连接到它。

通过使用条件拆分,您会将重复记录重定向到输出,您可以将它们写入表/文件。

使用 Cast Function (DT_I4) 将 [Count All] 转换为 Int

条件拆分转换将创建两个输出:

  • DuplicateRecords 重复记录
  • CorrectRecords 获取唯一记录

带上Multicast Transformation 并将Conditional Split TransformationDuplicateRecords 输出连接到它。

带上一个 OLE DB 目标并将来自 Conditional Split TransformationCorrectRecords 输出连接到它。

将数据查看器放在它们之间,以便您可以显示记录。您将实时将这些记录写入目标表/文件。

2。查找组件:

在控制流中添加Lookup task,并加入Excel文件任务。

Lookup Transformation Editor 中,指定连接管理器和缓存类型。

在指定如何处理没有匹配条目的行的下拉列表中,选择以下选项:

Redirect rows to no match output

单击连接并从下拉列表中指定目标表。您在同一个数据库中同时拥有源表和目标表。您也可以在此处创建单独的连接。

单击列,它会显示源表和目标表。 您想比较 Excel 文件和目标表上的 ID 列。从源中拖动 ID 列并将其移动到目标 ID 列。

从 SSIS 工具箱中添加 OLE DB destination。使用OLE DB destination 加入查找任务,它会打开以下输入-输出选择。

选择以下值:

  • 输出:查找不匹配输出:您将其附加到OLE DB destination(SQL Server 数据库中的表)
  • 输入:OLE DB 目标输入:例如,将其附加到平面文件目标

3. SSIS 排序结合脚本组件:

将您的源添加到数据流任务。 您需要对要用于重复数据删除的列进行排序。一般来说,如果你的源是一个数据库表,那么你应该在查询中添加一个GROUP BY 子句,否则你应该在你的源之后添加一个SORT Transformation。 在排序后的源代码之后添加一个脚本组件类型转换。

编辑Script Component 并转到Input Columns tab 并选择您要用于重复数据删除的所有列ReadOnly(与您用于排序的字段相同)。

转到输入和输出选项卡并将输出端口的名称从“输出 0”更改为“唯一”。还将 ExclusionGroup 更改为 1。

添加一个新输出并将其命名为 Duplicate 并将 ExlusionGroup 更改为 1。要将此新输出端口连接到输入端口,请更改 SynchronousInputID 属性并选择输入端口。

编辑脚本并复制以下代码。此脚本使用反射来获取所有选定的列,因此如果您更改输入列,则不必更改脚本。但请阅读编码 cmets。

// C# code
// This script automaticly compares the selected columns, but there is one 'bug':
// You have to edit and close this script again if you change input columns.
using System;
using System.Data;
using System.Reflection;                                // Added
using System.Text;                                      // Added
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Runtime.Wrapper;
 
[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public class ScriptMain : UserComponent
{
    // Create a variable to store the concatenated values for the previous row
    string previousRow = "";
 
    public override void Input0_ProcessInputRow(Input0Buffer Row)
    {
        // Create a variable to store the concatenated values of current row
        StringBuilder currentRow = new StringBuilder();
 
        foreach (PropertyInfo p in Row.GetType().GetProperties())
        {
            // We can't use the _IsNull columns, so ignore them. Also ignore the new output column
            if ((p.Name.ToLower().EndsWith("_IsNull") == false) && (p.Name.Equals("Duplicate") == false))
            {
                try
                {
                    // Concatenate value as string to variable
                    currentRow.Append(p.GetValue(Row, null).ToString() + "|");
                }
                catch (ArgumentException)
                {
                    // If the value is NULL (empty) then you can't get the value of it
                    currentRow.Append("NULL|");
                }
                catch (Exception ex)
                {
                    // Raise error because something unexpected went wrong
                    bool pbCancel = false;
                    this.ComponentMetaData.FireError(0, "MarkDuplicates", p.Name + ": " + ex.Message, string.Empty, 0, out pbCancel);
                }
            }
        }
 
        // Check if the current row and previous row are the same
        if (currentRow.ToString().Equals(previousRow))
        {
            // Redirect to duplicate output
            Row.DirectRowToDuplicate();
        }
        else
        {
            // Redirect to unique output
            Row.DirectRowToUnique();
        }
 
        // Fill previous row with current value for next check
        previousRow = currentRow.ToString();
    }
}

或 VB.Net :

' VB.Net code
' This script automaticly compares the selected columns, but there is one 'bug':
' You have to edit and close this script again if you change input columns.
 
Imports System
Imports System.Data
Imports System.Math
Imports System.Reflection                           ' Added
Imports System.Text                                 ' Added
Imports Microsoft.SqlServer.Dts.Pipeline.Wrapper
Imports Microsoft.SqlServer.Dts.Runtime.Wrapper
 
<Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute> _
<CLSCompliant(False)> _
Public Class ScriptMain
    Inherits UserComponent
 
    ' Create a variable to store the concatenated values for the previous row
    Dim previousRow As String = ""
 
    Public Overrides Sub Input0_ProcessInputRow(ByVal Row As Input0Buffer)
        ' Create a variable to store the concatenated values of current row
        Dim currentRow As StringBuilder = New StringBuilder()
 
        Dim p As PropertyInfo
        For Each p In Row.GetType().GetProperties()
            ' We can't use the _IsNull columns, so ignore them. Also ignore the new output column
            If ((p.Name.ToLower().EndsWith("_IsNull") = False) And (p.Name.Equals("Duplicate") = False)) Then
                Try
                    ' Concatenate value as string to variable
                    currentRow.Append(p.GetValue(Row, Nothing).ToString() + "|")
                Catch ex As ArgumentException
                    ' If the value is NULL (empty) then you can't get the value of it
                    currentRow.Append("NULL|")
                Catch ex As Exception
                    ' Raise error because something unexpected went wrong
                    Dim pbCancel As Boolean
                    Me.ComponentMetaData.FireError(0, "MarkDuplicates", p.Name + ": " + ex.Message, String.Empty, 0, pbCancel)
                End Try
            End If
        Next
 
        ' Check if the current row and previous row are the same
        If (currentRow.ToString().Equals(previousRow)) Then
            ' Redirect to duplicate output
            Row.DirectRowToDuplicate()
        Else
            ' Redirect to unique output
            Row.DirectRowToUnique()
        End If
 
        ' Fill previous row with current value for next check
        previousRow = currentRow.ToString()
    End Sub
End Class

添加两个目的地并将Data Flow Paths 连接到目的地。连接时,您必须选择输出端口。

不要忘记添加一些数据查看器用于测试目的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-25
    • 2013-05-08
    • 1970-01-01
    • 2014-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多