【问题标题】:In SSIS, How to lookup ID for value, if no match, insert value and return ID在 SSIS 中,如何查找值的 ID,如果不匹配,则插入值并返回 ID
【发布时间】:2019-11-06 14:12:14
【问题描述】:

使用 SSIS,我将分阶段提取加载到其主数据库中。该过程的一部分是使用 LOOKUP 来获取字符串值的 ID,如果它不存在,则将其插入引用表(使用 OLE DB COMMAND)并通过后续查找返回该 ID。

LOOKUP 表示即使插入后前 50 个值也不匹配。 有没有办法解决这个问题? 或者,我应该尝试其他方法吗?

一些研究/尝试...

  1. 最初,没有返回匹配项。我必须将所有查找更改为“无缓存”,以便重新加载引用表(它们非常小,所以我怀疑我会遇到很大的性能问题)。

  2. 我见过的另一种方法是多播到不同的查找中(基于我正在查找的列),然后在我成功插入/查找它们后将它们合并在一起。但根据我的阅读,这种方法存在严重的性能问题。

我希望查找匹配或不匹配。如果不匹配,插入新值;然后,再次查找 ID 的值(如果不匹配,则失败)。合并原始匹配和原始不匹配以进行下一次查找。

【问题讨论】:

  • 您的模式会多次插入(或尝试插入)相同的“不匹配”

标签: sql-server ssis lookup


【解决方案1】:

试试这个模式:

1.You are multicasting the dataset and grouping by just your lookup column
2.inserting your lookup and adding the scopeidentity(lookupid) to you grouped data
3.joining in the data you inserted to effective add your lookup value to every row
4.unioning your data back in

我不肯定,但您可能需要添加排序才能使用合并连接。

【讨论】:

  • 注意我使用了一个脚本组件来插入和返回作用域标识。我认为您可以使用 OLE 命令执行此操作,但我不确定。我发现管理 c# 代码比查找 GUI 属性更容易。
  • 这也会将所有不匹配的内容发送到插入路径。这样可以避免“错过下一个50左右”。请注意,Aggregate 和 Merge Join 是等待处理所有记录的停止器对象。
  • 另外,我没有详细介绍这些对象中的任何一个,因为它们本身就是问题。但这应该为您提供工作模板,让您的项目顺利运行。
  • 经过一天的故障排除,我终于让它工作了!我认为组件的数量会降低性能,但我现在愿意为工作模型牺牲性能。我会发布最终解决方案
  • 希望路径很少被使用,并且所有查找都具有完整的维度。
【解决方案2】:

SSIS 数据流

Here is the final SSIS data flow model... 根据@KeithL 的建议,我在合并连接之前添加了排序。

脚本组件

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

public class ScriptMain : UserComponent
{
    IDTSConnectionManager100 serverConMgr;

    public override void PreExecute()
    {
        base.PreExecute();
        serverConMgr = this.Connections.Connection;
    }
    public override void Input0_ProcessInputRow(Input0Buffer Row)
    {
        using (SqlConnection serverCon = new SqlConnection(serverConMgr.ConnectionString))
        {
            SqlCommand sql = new SqlCommand(
            "INSERT INTO DIM.CONTRIBUTOR (CONTRIBUTOR) VALUES ('" + Row.CONTRIBUTOR + "') " +
            "\n SELECT CAST(SCOPE_IDENTITY() AS INT) AS 'ID'"
            , serverCon);

            serverCon.Open();

            SqlDataReader data = sql.ExecuteReader();

            while (data.Read())
            {
                Row.CONTRIBUTORID = data.GetInt32(0);
            }

            data.Close();
        }
        
    }
}

“脚本组件”是最棘手的部分。它插入新值并检索相应的 ID。下面是该脚本的代码。

注意 3 件重要的事情...

  1. 数据库连接管理器(在本例中,名为“Connection”,必须是 ADO.Net 连接)
  2. Row.CONTRIBUTOR_ID 是我在脚本编辑器的“输入和输出”部分手动配置为输出的行
  3. SqlDataReader 的“GetInt32()”方法不适用于 SCOPE_IDENTITY,除非 SCOPE_IDENTITY 在 sql 命令中显式转换为 int

这里有一些与脚本相关的其他注释...

  1. 你可以insert and return SCOPE_IDENTITY through OLE DB command,但它相当复杂
  2. 这是对how to retrieve data using SqlDataReader 的 Microsoft 文档参考

【讨论】:

  • 一个建议:在没有阅读器部分的情况下尝试这个... Row.CONTRIBUTORID = Convert.ToInt(sql.ExecuteScalar()); ExecuteScalar 返回第一行结果的第一列中的值,即查询中的 scope_identity。
  • 还有人会告诉你关于 SQL 注入的事情。你应该使用参数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-28
  • 1970-01-01
  • 1970-01-01
  • 2019-09-06
  • 1970-01-01
  • 2013-08-14
相关资源
最近更新 更多