如何将 XML 文件中的 Excel 序列日期编号转换为 SSIS 包中 SQL 服务器的 mm/dd/yyyy?
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 序列日期编号,而不是通常的 mm/dd/yyyy 日期。我在向我现有的 SSIS 包添加数据转换时遇到问题,因为序列号在 XML 文件中,而不是 excel 文件中。
SSIS 包清理并加载一个 xml 文件到 SQL 服务器 table。
有人有什么想法吗?我在 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 错误的偏移值。
然后将我的第一个表达式简化为
DATEADD("Day", [CONTRACT_START_DATE] - [CONTRACT_START_DATE_Offset], [BaseDate])
如果您真的想找出可能出错的地方,我什至会考虑将那里的数学逻辑 Col1 - Col1_Offset
封装到前体派生列中,这样我就可以将数据 tap/data 查看器并捕获值。
作为最小复制,我创建了一个包含 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,请确保您添加的是新列,而不是试图替换现有列。
我收到了一个 XML 文件,其中日期字段是 Excel 序列日期编号,而不是通常的 mm/dd/yyyy 日期。我在向我现有的 SSIS 包添加数据转换时遇到问题,因为序列号在 XML 文件中,而不是 excel 文件中。
SSIS 包清理并加载一个 xml 文件到 SQL 服务器 table。
有人有什么想法吗?我在 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 错误的偏移值。
然后将我的第一个表达式简化为
DATEADD("Day", [CONTRACT_START_DATE] - [CONTRACT_START_DATE_Offset], [BaseDate])
如果您真的想找出可能出错的地方,我什至会考虑将那里的数学逻辑 Col1 - Col1_Offset
封装到前体派生列中,这样我就可以将数据 tap/data 查看器并捕获值。
作为最小复制,我创建了一个包含 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,请确保您添加的是新列,而不是试图替换现有列。