Excel中的SQL Server Datetime对象持续重新格式化问题

Posted

技术标签:

【中文标题】Excel中的SQL Server Datetime对象持续重新格式化问题【英文标题】:SQL Server Datetime object persistent reformatting issue in Excel 【发布时间】:2017-01-20 10:41:48 【问题描述】:

我在使用 Excel 2013 中的 SQL Server DATETIME 对象时遇到了一个烦人的问题。该问题已在 SO 中多次说明,我知道解决方法是重新格式化 Excel 中的 DATETIME 对象这样做:

右键单击单元格 选择单元格格式 选择自定义 在类型:输入字段中输入yyyy-mm-dd hh:mm:ss.000

这很好用,但我讨厌每次都这样做。除了创建宏之外,是否有永久性的解决方法?我需要保持DATETIME 对象的粒度,所以我不能使用SMALLDATETIME。我目前在 win7 机器上使用 Microsoft SQL Server Management Studio 2008 r2。

提前致谢。

-Stelio K.

【问题讨论】:

您是如何将其导入 Excel 的?因为这也可以通过宏来完成,将所有步骤缩小到单击按钮。还有数据源链接进入表格,您可以对其进行格式化。 您似乎无法在没有其他麻烦的情况下修改 Excel 的默认粘贴行为。虽然很烦人,但我认为这是你阻力最小的道路。 保存特殊电子表格是一步,转换为日期时间是一步。如果它们都是临时查询,那么日期时间列的位置是可变的,所以请告诉我您的解决方案如何解决问题。 如果您考虑一下这些词的含义,就会出现“默认粘贴行为”。这是 Excel 在粘贴时默认执行的操作。在我看来,您的意见没有建设性。 @StelioK 您(或最终用户)可以在任何版本的 Excel 2013 中使用 Power Query 来执行您想要的任何类型的操作,包括应用类型和格式。无需使用代码。 【参考方案1】:

没有任何代码,很难猜出如何数据从 SQL Server 到 Excel。我认为这不是通过数据连接,因为 Excel 直接将数据显示为日期不会有任何问题。

数据连接呢?

Excel 在处理数据连接时不支持任何类型的格式或任何有用的设计器。该功能由 Power Query 或数据透视表设计器提供。 Power Query 已集成在 Excel 2016 中,可用于 Excel 2010+ 的下载。

为什么需要格式化日期

Excel 不保留类型信息。一切都是字符串或数字,其显示由单元格的格式决定。

日期使用 OLE 自动化格式存储为小数 - 整数部分是自 1900-01-01 以来的日期数,小数部分是时间。这就是System.DateTime 具有FromOADateToOADate 功能的原因。

要创建带有日期的 Excel 工作表,您应该在生成单元格的同时设置单元格格式。

如何格式化单元格

如果您使用 Open XML SDK 或 EPPlus 之类的库,则相对而言这样做。以下示例根据客户列表创建 Excel 工作表:

static void Main(string[] args)

    var customers = new[]
    
        new Customer("A",DateTime.Now),
        new Customer("B",DateTime.Today.AddDays(-1))
    ;
    File.Delete("customers.xlsx");
    var newFile = new FileInfo(@"customers.xlsx");
    using (ExcelPackage pck = new ExcelPackage(newFile))
                    
        var ws = pck.Workbook.Worksheets.Add("Content");

        // This format string *is* affected by the user locale!
        // and so is "mm-dd-yy"!
        ws.Column(2).Style.Numberformat.Format = "m/d/yy h:mm";

        //That's all it needs to load the data
        ws.Cells.LoadFromCollection(customers,true);
        pck.Save();
    

代码使用 LoadFromCollection 方法直接加载客户列表,无需处理单元格。 true 表示生成了一个header。

有等效的方法可以从其他来源加载数据:LoadFromDatatable、LoadFromDataReader、CSV 数据的 LoadFromText,甚至是锯齿状对象数组的 LoadFromArrays。

奇怪的是,指定m/d/yy h:mmmm-dd-yy 格式使用用户的语言环境进行格式化,不是美国格式!这是因为这些格式内置在 Excel 中,并被视为与区域设置相关的格式。在日期格式列表中,它们以星号显示,表示它们受用户区域设置的影响。

这种奇怪的原因是,当 Excel 10 年前迁移到基于 XML 的 XLSX 格式时,出于向后兼容的原因,它保留了旧 XLS 格式的怪癖。

当 EPPlus 保存 xlsx 文件时,它会检测到它们并存储对内置格式 ID(分别为 22 和 14)的引用,而不是存储整个格式字符串。

查找格式 ID

标准格式 ID 列表显示在 Open XML 标准的NumberingFormat element documentation page 中。 Excel 最初定义的 ID 为 0(常规)到 49。

EPPlus 不允许直接设置 ID。它检查格式字符串并仅映射格式 0-49,如 ExcelNumberFormat 的 GetBfromBuildIdFromFormat 方法中所示。为了获得 ID 22,我们需要将 Format 属性设置为 "m/d/yy h:mm"

另一个技巧是检查现有工作表的样式表。 xlsx 是一个 XML 文件的压缩包,可以使用任何解压缩工具打开。样式存储在xl\styles.xml 文件中。

【讨论】:

我在我的 OP 中声明数据只是简单的复制和粘贴。 @StelioK 您可以考虑将其作为编辑而不是 cmets 放入您的帖子中,特别是在运行查询后从 SSMS“结果”窗格中复制。我认为我最初的假设是正确的,但是对于您可能从事的工作,有无数的选择有一些开放的解释。 @StelioK 您可以根据需要使用“导出数据”向导直接生成 Excel 文件并避免格式猜测。实际上,您只是在复制文本。 Excel 会识别某些格式,但不会根据猜测更改样式。

以上是关于Excel中的SQL Server Datetime对象持续重新格式化问题的主要内容,如果未能解决你的问题,请参考以下文章

从 excel 导入数据时防止 SQL Server 2008 中的行重复

如何将sql server中的大量数据导出到excel文件中

SQL Server、Excel 和 MS Access 中的日期差异

如何将excel表中的数据导入到sql server表中?

如何将 Excel 工作表中的行插入 SQL Server 2005 或 oracle

从Excel vba中的SQL Server数据中检索/创建记录集