【问题标题】:SSIS Extract links from Excel cells to load into SQLSSIS 从 Excel 单元格中提取链接以加载到 SQL
【发布时间】:2020-04-19 12:21:51
【问题描述】:

问题:

我有一个 SSIS 包,它遍历 100 多个 Excel 文件并读取数据,然后将内容复制到 SQL Server 表中。在这些 Excel 文件中,这一列具有超链接。列文本本身类似于 DSH-LN-4,但在 Excel 中单击它会打开一个包含一些图像的文件夹。如何复制此列中的基础链接而不是单元格中的实际文本?

到目前为止我做了什么:

我还没有真正尝试过任何事情,因为我在 SSIS 中完全没有找到有关如何执行此操作的资源。无法手动向 Excel 文件添加一列,因为有 100 个文件。我发现的唯一资源是在this SO Question,但这并不表示在不手动操作 Excel 文件的情况下执行此操作的过程。

我想要什么:

在我的 ForEach 循环容器中,我有一个数据流任务,它获取 Excel 内容并将其推送到 SQL 表中。包含超链接的列称为PhotoReference(因为这些超链接会打开包含照片的文件夹)。我希望 PhotoReference 列复制单元格的底层超链接并将其添加到 SQL 列中。

例如,我希望 PhotoReference 列包含以下内容:

www.companyname.box.com/asjdfbgkjb134kjbsdafo2bm21n4bk

如果我能做到这一点,我的 Power BI 报告会根据这些基础数据运行,其中可能包含可直接打开图像的可点击文本。

任何帮助将不胜感激。

更新:

我可以尝试两种不同的方法从我的专栏中提取超链接,但每种方法都有自己的问题:

方法 1: 我在 ForEach 容器中添加了一个脚本任务组件,并在循环每个 Excel 文件时,使用 Microsoft.Office.Interop.Excel.Hyperlinks 程序集从我的 Excel 列中获取超链接。但是,我不知道之后该怎么办。我认为唯一要做的就是用我提取的超链接覆盖 Excel 列的内容,但我真的不想以任何方式更改我的 Excel 文件。

方法 2: 我在 Excel 源和 SQL 目标之间的数据流任务中添加了一个脚本组件对象。在这种方法中,我几乎无法走得那么远,因为自动生成的Input0_ProcessInputRow 方法具有Input0Buffer 类型的参数Row。我无法将任何 Microsoft.Office.Interop.Excel 属性应用于我的 Input0Buffer 对象。所以我被卡住了。

【问题讨论】:

  • 在 for each 循环容器中,您应该在数据流任务中读取 Excel 之前添加一个脚本任务以将内容提取到另一列。稍后我会尽力提供详细的答案
  • 谢谢@Hadi,我希望能更详细地解释如何做到这一点。我正在努力使用Input0Buffer Row 我在脚本组件方法中使用Interop.Excel 程序集来提取超链接。

标签: sql-server excel ssis etl excel-interop


【解决方案1】:

如果您必须有权更改 excel 文件,您只需在数据流任务之前添加一个脚本任务,以将 URL 列值替换为超链接。

在这个答案中,我将提供一步一步的解决方案来解决这个问题:

创建 Excel 示例

首先,我创建了一些包含以下列的 Excel 文件:

  • 名字(文字)
  • 姓氏(文字)
  • 年龄(数字)
  • 照片(超链接)

文件内容如下:

创建 SSIS 包

  1. 首先,您必须添加一个链接到您需要导入的 Excel 文件之一的 Excel 连接管理器。以及一个用于连接 SQL Server 实例的 OLE DB 连接管理器。
  2. 您必须添加一个字符串类型的 SSIS 变量,以便在使用 foreach 枚举器时存储 Excel 文件路径

  1. 添加一个 Foreach 循环容器并将其配置为循环遍历 Excel 文件,如下图所示:

  1. 在 Foreach 循环容器中添加一个脚本任务和一个数据流任务,如下图所示:

  1. 现在,打开数据流任务并添加 Excel 源和 OLE DB 目标并配置它们之间的列映射。

  2. 打开脚本任务配置,并选择 ExcelFilePath 变量(在步骤 2 中创建)作为只读变量,如下图所示:

  1. 现在,打开脚本编辑器并在解决方案资源管理器窗口中,右键单击引用图标并单击“添加引用...”
  2. 出现添加参考目录时,单击 COM 选项卡,然后搜索 Excel,然后您应该从结果中选择 Excel 对象库,如下图所示:

  1. 另外,请务必添加 Microsoft.CSharp.dll 引用。
  2. 您应该在脚本顶部添加以下行:

    using Excel = Microsoft.Office.Interop.Excel;
    using System.Runtime.InteropServices;
    
  3. 在 Main() 函数中添加以下行:

    Excel.Application excel = new Excel.Application();
    string originalPath = Dts.Variables["User::ExcelFilePath"].Value.ToString();
    Excel.Workbook workbook = excel.Workbooks.Open(originalPath);
    Excel.Worksheet worksheet = (Excel.Worksheet)workbook.Worksheets[1];
    Excel.Range usedRange = worksheet.UsedRange;
    int intURLColidx = 0;
    
    excel.Visible = false;
    excel.DisplayAlerts = false;
    
    for (int i = 1; i <= usedRange.Columns.Count; i++)
    {
    
    
        if ((worksheet.Cells[1, i] as Excel.Range).Value != null &&
            (string)(worksheet.Cells[1, i] as Excel.Range).Value == "Photo")
        {
    
            intURLColidx = i;
            break;
    
        }
    
    
    
    }
    
    for (int i = 2; i <= usedRange.Rows.Count; i++)
    {
    
        if ((worksheet.Cells[i, intURLColidx] as Excel.Range).Hyperlinks.Count > 0)
        {
            (worksheet.Cells[i, intURLColidx] as Excel.Range).Value2 = (worksheet.Cells[i, intURLColidx] as Excel.Range).Hyperlinks.Item[1].Address.ToString();
        }
    }
    
    workbook.Save();
    
    Marshal.FinalReleaseComObject(worksheet);
    
    workbook.Close(Type.Missing, Type.Missing, Type.Missing);
    Marshal.FinalReleaseComObject(workbook);
    
    excel.Quit();
    Marshal.FinalReleaseComObject(excel);
    Dts.TaskResult = (int)ScriptResults.Success;
    

在上面的行中,首先我们搜索包含超链接的列索引(在本例中列名是“照片”,然后我们将检查每一行,如果超链接地址不为空,我们将用这个超链接地址替换列值)

  1. 最后,确保将 Excel 连接管理器配置为使用表达式从创建的变量值(步骤 2)中读取文件路径:

实验

运行包后,如果我们打开一个 Excel 文件,我们会看到 Cell 值被替换为 URL:

如下图所示,数据成功导入SQL Server:


参考文献

【讨论】:

  • 非常感谢,我现在正在做这个。我本来希望有一种方法可以在不更改 Excel 文件的情况下做到这一点,但无论如何我都在制作云控制的 Excel 文件的本地副本,所以这并不重要。我会试试这个并回复你。
  • @CrazyCucumber 如果您无法更改 Excel 文件,则应使用脚本组件循环行、更改超链接列值、生成 SSIS 缓冲区行并关闭 Excel 而不保存。但这是一种更复杂的方法。我认为复制文件并使用脚本任务更容易
  • 是的!我看到你的 Excel 文件格式后想通了。非常感谢,现在运行它。
  • DelayValidation 已经是 true,因为 ConnectionManager 需要表达式。不过,Excel 过程确实奏效了。有十五个开放!哈哈。还要看看可能结束 SSIS 中的进程,所以这项工作没有完成并留下一个草率的烂摊子。你,善良的人类,太棒了!太感谢了!我会尽快奖励赏金。 P.S.:我做了一个改变:删除了提到intURLColidx的整个部分。我知道该 URL 存在,并且我知道它存在于第 21 列中。所以我只是硬编码了它。
  • @CrazyCucumber 很高兴听到这个消息。奇怪的是,最后几行是为了杀死进程,看起来好像少了点什么。关于赏金,它将在您将此答案标记为接受后 7 天后自动授予。
【解决方案2】:

您可能需要做一些涉及 Excel COM API 或宏的黑客操作。事实上,因为您应该远离在 SSIS 中使用 Office COM API。

您可以预处理 excel 以使用 SSIS 中的非标准操作获取该值,例如使用脚本组件。

这些是您使用脚本组件导入该数据需要遵循的步骤:

  1. 拖放一个脚本组件并选择“源”作为脚本选项类型。

  2. 默认情况下,脚本语言是 Microsoft Visual C# 2008,我使用 Microsoft Visual Basic 2008 完成了这个示例。如果需要,可以更改。

  3. 在“数据类型属性”中使用正确的数据类型定义输出列

  4. 编辑脚本。在 IDE 中,您应该添加参考:

    • Microsoft.Excel 11.0 对象库

(如果该引用不起作用,请尝试使用 Microsoft.Excel 5.0 对象库)

  1. 最后,写一些代码:

Imports Microsoft.Office.Interop.Excel 

Public Overrides Sub getHyperlink()
  Dim oExcel As Object = CreateObject("Excel.Application")
  Dim FileName As String
  FileName = Variables.FileName
  Dim oBook As Object = oExcel.Workbooks.Open(FileName)
  Dim oSheet As Object = oBook.Worksheets(1)
  Output0Buffer.AddRow()
  // change A1 with your correct col & row
  Output0Buffer.Address = cell.range("A1").Hyperlinks(1).Address & "#" & cell.range("A1").Hyperlinks(1).SubAddress

End Sub

(请记住,这是一个可能无法运行的代码,仅作为说明)

您可以在此处查看 C# 代码: C# Script in SSIS Script Task to convert Excel Column in "Text" Format to "General"

脚本方法的唯一问题是您需要拥有 Excel 已安装运行时。

这里有更多关于脚本组件的信息: https://www.tutorialgateway.org/ssis-script-component-as-transformation/

【讨论】:

  • 感谢您的回答。我现在正在处理脚本组件。我遇到的唯一问题是,我应该将脚本组件添加为数据流任务中的转换脚本组件吗?还是应该将其添加到数据流任务之外?我想出了一种将其添加到外部并遍历超链接的方法,但是我不确定如何在某处编写读取的超链接。如果我在数据流任务中使用它,我不确定如何在Input0Buffer row 对象中使用 Excel com 对象。对此有何指导?
猜你喜欢
  • 2017-06-03
  • 1970-01-01
  • 2011-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多