SSIS 从 Excel 个单元格中提取链接以加载到 SQL

SSIS Extract links from Excel cells to load into SQL

问题:

我有一个 SSIS 包,它循环访问 100 多个 Excel 文件并读取数据,然后将内容复制到 SQL 服务器 Table。在这些 Excel 文件中,这一列有 hyperlinks。列文本本身表示类似于 DSH-LN-4,但在 Excel 中单击它会打开一个包含一些图像的文件夹。如何复制此列中的基础 link 而不是单元格中的实际文本?

到目前为止我尝试了什么:

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

我想要什么:

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

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

www.companyname.box.com/asjdfbgkjb134kjbsdafo2bm21n4bk

如果我能做到这一点,我的 Power BI 报告 运行 可以包含可直接打开图像的可点击文本。

如有任何帮助,我们将不胜感激。

更新:

我能够尝试两种不同的方法从我的专栏中提取 hyperlinks,但每种方法都有自己的问题:

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

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

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

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

使用脚本组件导入该数据需要遵循以下步骤:

  1. 拖放脚本组件和select "source"作为脚本选项类型。

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

  3. 在 "data type properties"

  4. 中使用正确的数据类型定义输出列
  5. 编辑脚本。在 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"

The only issue with the script method is you need to have the Excel runtime installed.

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

如果您必须有权更改 excel 文件,您可以简单地在数据流任务之前添加一个脚本任务,以将 URL 列值替换为 hyperlink .

在这个回答中,我将提供一个循序渐进的解决方案来解决这个问题:

创建 Excel 个样本

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

  • 名字(文字)
  • 姓氏(文字)
  • 年龄(人数)
  • 照片(超级link)

文件内容如下所示:

正在创建 SSIS 包

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

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

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

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

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

  1. 现在,打开脚本编辑器并在解决方案资源管理器中 window,右键单击引用图标并单击 "Add Reference..."
  2. 当出现Add reference catalog时,点击COM选项卡,然后搜索Excel,那么你应该select the Excel Object Library from the results as shown in the results下图:

  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;
    

在上面的行中,首先我们搜索包含 hyperlink 的列索引(在这个例子中,列名是 "Photo",然后我们将检查每行如果 Hyperlink 地址不为空,我们将用这个 hyperlink 地址替换列值)

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

实验

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

如下图所示,数据导入成功到SQL服务器:


参考资料

  • Missing compiler required member 'microsoft.csharp.runtimebinder.binder.convert'
  • Extracting a URL from hyperlinked text in Excel cell