【问题标题】:How do I convert Excel Serial Date Numbers in an XML file to mm/dd/yyyy for SQL Server in an SSIS Package?如何将 XML 文件中的 Excel 序列号转换为 SSIS 包中 SQL Server 的 mm/dd/yyyy?
【发布时间】:2020-09-22 22:15:04
【问题描述】:

我收到了一个 XML 文件,其中日期字段是 Excel 序列日期编号,而不是通常的 mm/dd/yyyy 日期。我无法将数据转换添加到我预先存在的 SSIS 包,因为序列号在 XML 文件中,而不是在 excel 文件中。

SSIS 包清理并将一个 xml 文件加载到 SQL Server 表中。

有人有什么想法吗?我在 Visual Studios 2015 工作,仅供参考。

XML 数据片段:

    <AGREEMENT_CODE>1960-EMPR</AGREEMENT_CODE>
        <AGREEMENT_NAME>1960-Legacy Employer Conversion 
    Default</AGREEMENT_NAME>
        <AGREEMENT_TYPE>MBA</AGREEMENT_TYPE>
        <FUND_TYPE>Health &amp; Pension</FUND_TYPE>
        <CONTRACT_START_DATE>21916</CONTRACT_START_DATE>
        <EMPLOYER_ID>25568</EMPLOYER_ID>
        <EMPLOYER_NAME>10409</EMPLOYER_NAME>
        <BILLING_ENTITY_CODE>ACT III TELEVISION, L.P.</BILLING_ENTITY_CODE>
        <BILLING_ENTITY_NAME>10409</BILLING_ENTITY_NAME>
        <PARTICIPATION_START_DATE>ACT III TELEVISION, L.P. 
   </PARTICIPATION_START_DATE>
        <PARTICIPATION_SIGNED_DATE>35917</PARTICIPATION_SIGNED_DATE>

Excel 序列号位于第 6 行和第 13 行。它们是 5 位数字。

【问题讨论】:

    标签: sql-server excel xml date ssis


    【解决方案1】:

    Excel 中的日期实际上是一个数字,代表(出于所有意图和目的)自 1899 年 12 月 30 日以来的天数。但是下面有一个警告。

    因此,您可以使用DATEADD(day, @yourDateNum, '18991230') 将数字转换为日期

    需要注意的是,Microsoft(以及之前的 Lotus 1-2-3)在日期计算中存在错误:they assume 1900 is a leap year,但事实并非如此。因此,计数中有额外的一天,我已经调整了上面的公式以考虑到这一点。然而,结果是这个公式不适用于 1900 年 3 月 1 日之前的日期。

    请在投入生产前用已知值检查您的公式!

    【讨论】:

    • 感谢您的回复。我现在遇到的问题是我无法从 DT_WSTR (255) 更改派生列数据类型,并且它说 DATEADD 函数不支持该数据类型。我可以仅在脚本中派生列吗?
    【解决方案2】:

    我使用了十多年的代码现在来自一个已不存在的站点

        /// <summary>
        /// Seriously?  For the loss
        /// <see cref="http://www.debugging.com/bug/19252"></see>
        /// </summary>
        /// <param name="excelDate">Number of days since 1900-01-01</param>
        /// <returns>The converted days to date</returns>
        public static DateTime ConvertXlsdtToDateTime(int excelDate)
        {
            DateTime dt = new DateTime(1899, 12, 31);
    
            // adjust for 29 Feb 1900 which Excel considers a valid date
            if (excelDate >= 60)
            {
                excelDate--;
            }
    
            return dt.AddDays(excelDate);
        }
    

    如果要在派生列任务中使用它,则需要将 C# 转换为 SSIS 表达式语言。我们将使用三元运算符(boolean) ? truevalue : falsevalue 来实现这一点

    DATEADD("Day", [CONTRACT_START_DATE] - ([CONTRACT_START_DATE] >= 60 ? 1 : 0), (DT_DATE)"1899-12-30")
    

    通常,我的数据流中有两个派生列组件,因为这是调试事物的唯一方法。在您的情况下,我会让第一个派生列将 1 + Excel 列数添加到数据流中。

    注意,我在这里展示的赋值 = 是您放入派生任务中 Derived Column NameExpression 列的值的简写语法

    BaseDate = (DT_DATE)"1899-12-30"
    CONTRACT_START_DATE_Offset = [CONTRACT_START_DATE] >= 60 ? -1 : 0
    PARTICIPATION_SIGNED_DATE_Offset = [PARTICIPATION_SIGNED_DATE] >= 60 ? -1 : 0
    

    等等。现在我可以检查我是否正确处理了 1900 错误的偏移值。

    然后将我的第一个表达式简化为

    DATEADD("Day", [CONTRACT_START_DATE] - [CONTRACT_START_DATE_Offset], [BaseDate])
    

    如果您真的想找出可能出错的地方,我什至会考虑将 Col1 - Col1_Offset 那里的数学逻辑封装到前导派生列中,这样我就可以在其上放置一个数据挖掘/数据查看器并捕捉价值。

    作为一个最小的复制品,我创建了一个包含 OLESRC 组件的包,该组件将我们的 CONTRACT_START_DATE 添加到数据流中

    SELECT 35 AS CONTRACT_START_DATE
    UNION ALL SELECT 21916
    

    使用第一个表达式的我的派生列“OneShot”添加列“OneShot”

    DER 多语句从第二组表达式中添加 BaseDate 和 CONTRACT_START_DATE_Offset 值

    DER CSD 使用第三个表达式将 ContractStartDate 添加到数据流中。

    在上图中,您可以看到数据查看器的结果(以及此时的元数据副本)。使用 DATEADD 函数 - DT_DBTIMESTAMP 后,我的数据类型符合预期。

    如果您的类型显示为 DT_WSTR,请确保您正在添加新列而不是尝试替换现有列。

    【讨论】:

    • 感谢您的回复。我现在遇到的问题是我无法从 DT_WSTR (255) 更改派生列数据类型,并且它说 DATEADD 函数不支持该数据类型。我可以仅在脚本中派生列吗?
    • 向派生列添加新列(不要尝试替换现有的)
    • 分离步骤效果很好,感谢您的帮助@billinkc
    猜你喜欢
    • 2018-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-22
    • 2011-03-18
    • 1970-01-01
    相关资源
    最近更新 更多