问题描述
我收到了一个XML文件,其中日期字段是Excel序列日期编号,而不是通常的mm / dd / yyyy日期。我无法在以前存在的SSIS包中添加数据转换,因为序列号在XML文件中,而不是Excel文件中。
SSIS包清除一个XML文件并将其加载到sql Server表中。
有人有什么想法吗?我正在使用Visual Studios 2015 fyi。
XML数据段:
<AGREEMENT_CODE>1960-EMPR</AGREEMENT_CODE>
<AGREEMENT_NAME>1960-Legacy Employer Conversion
Default</AGREEMENT_NAME>
<AGREEMENT_TYPE>MBA</AGREEMENT_TYPE>
<FUND_TYPE>Health & 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位数字。
解决方法
Excel中的日期实际上是一个数字,代表(出于所有意图和目的)自1899年12月30日以来的天数。但是下面有一个警告。
因此,您可以使用DATEADD(day,@yourDateNum,'18991230')
需要说明的是,Microsoft(及其之前的Lotus 1-2-3)在日期计算中存在错误:they assume 1900 is a leap year,但实际上没有。因此,这需要多花一天的时间,因此我已经调整了上面的公式以考虑到这一点。但是结果是,该公式不适用于1900年3月1日之前的日期。
在投入生产之前,请检查具有已知值的公式!
,我使用了十多年的代码现在来自一个已经不存在的站点
/// <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 + Number of Excel列到数据流中。
注意,这里显示的赋值=
是您在派生任务的Derived Column Name
和Expression
列中输入的值的简写语法
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 bug的偏移值。
然后将我的第一个表达式简化为
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 Multistatement从第二组表达式中添加BaseDate和CONTRACT_START_DATE_Offset值
DER CSD使用第三个表达式将ContractStartDate添加到数据流中。
在上图中,您可以看到数据查看器的结果(以及此时的元数据副本)。使用DATEADD函数DT_DBTIMESTAMP后,我的数据类型符合预期。
如果您的类型显示为DT_WSTR,请确保您要添加新列,而不是尝试替换现有列。