【问题标题】:Trouble inserting dates into Access DB - non existing hour due to timechange无法将数据插入 Access DB - 由于时间变化,时间不存在
【发布时间】:2013-12-06 16:35:25
【问题描述】:

我正在编写一个小导入例程来插入来自 excel 的测量数据以进行访问。在我的 excel 输入文件中,我得到了每小时忽略时间更改为夏令时的值,因此每个日期都将比前一个日期晚 1 小时。没有重复,没有丢失的日期。

现在我使用 poi 读取数据,然后尝试使用准备好的语句将数据批量插入 Access 数据库。但是我在执行批处理时总是遇到一般错误。查看数据库,我看到在“2011.03.27 01:00”之前插入的所有数据,但插入的下一个和最后一个日期是“2011.03.27 03:00”,其值对应于我的输入数据中的“2011.03.27 02:00” .

不知何故,在插入数据时,日期“2011.03.27 02:00”被隐式转换为“2011.03.27 03:00”(没有警告或错误),并且由于我的日期列被标记为主键,插入失败时试图插入真正的 3'o'clock 数据。

有什么方法可以防止这种转换发生吗?我知道日期“2011.03.27 02:00”不存在(或至少等于“2011.03.27 03:00”),但为了数据的一致性,我需要正确插入此日期。

这是我的代码:

        myDBConn = DriverManager.getConnection("jdbc:odbc:mydb");
        state = myDBConn.prepareStatement("Insert into myTable values(?,?,?)");
        for(int i=0;i<numberOfObjects;i++){
            state.clearBatch();
            for(int j=0;j<numberOfHours;j++){
                state.setString(1,names[i]);
                state.setTimestamp(2,dates[j]);
                state.setDouble(3, data[i][j]);
                state.addBatch();
            }
            state.executeBatch();
        }
        state.close();
        myConn.close();

我已经确保 dates[] 包含正确的日期并且没有重复。执行批处理时似乎确实发生了转换...

【问题讨论】:

  • 您可能不应该以特定于时区的格式存储,使用 UTC 之类的格式更合适,因为它是通用的,并且不会受到夏令时等因素的影响。见:stackoverflow.com/questions/2532729/…
  • 我想尝试一下,但是我应该以哪种格式存储日期?我不能在批量插入语句中使用 joda.DateTime,因为它只接受日期或时间戳。有没有办法在java中创建一个非时区特定的日期或时间戳?

标签: java sql date ms-access bulkinsert


【解决方案1】:

避免时区/夏令时问题的最直接方法可能是将 Excel 数据直接导入 Access 数据库,完全绕过 Java Date 复杂性。给定一个名为“measurements.xls”的 Excel 文件,其中包含“Sheet1”中的以下数据

还有一个名为“myDb.mdb”的新的空 Access 数据库,以下 Java 代码将使用旧的 Microsoft Access ODBC (Jet) 驱动程序将 Excel 数据直接导入 Access

import java.sql.*;

public class ImportFromExcelMain {

    public static void main(String[] args) {
        try {
            Connection con = DriverManager.getConnection(
                    "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};" + 
                    "DBQ=C:\\__tmp\\test\\measurements\\myDb.mdb;");
            Statement st = con.createStatement();
            st.execute(
                    "SELECT * INTO myTable " +
                    "FROM [Excel 8.0;HDR=YES;IMEX=2;DATABASE=C:\\__tmp\\test\\measurements\\measurements.xls].[Sheet1$];");
            st.close();
            con.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

}

结果,在 Access 中:

编辑重新:新信息

直接导入原始 Excel 数据(以避免日期错误)然后“取消透视”它可能会更容易。以下修改后的代码已使用如下所示的 Excel 工作表进行测试:

以及具有以下结构的现有 Access 表

import java.sql.*;
import java.util.*;

public class ImportFromExcelMain {

    public static void main(String[] args) {
        try {
            Connection con = DriverManager.getConnection(
                    "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};" + 
                    "DBQ=C:\\__tmp\\test\\measurements\\myDb.mdb;");
            Statement st = con.createStatement();

            try {
                st.execute("DROP TABLE [excelImport]");
            } catch (Exception e) {
                if(!e.getMessage().contains("Table 'excelImport' does not exist."))
                    throw(e);
            }

            // import raw data from Excel directly into Access
            st.execute(
                    "SELECT * INTO [excelImport] " +
                    "FROM [Excel 8.0;HDR=YES;IMEX=2;DATABASE=C:\\__tmp\\test\\measurements\\measurements.xls].[Sheet1$];");

            // grab an empty ResultSet so we can look at the column names
            st.execute("SELECT * FROM excelImport WHERE False");
            ResultSet rs = st.getResultSet();
            ResultSetMetaData rsmd = rs.getMetaData();
            String timeStampColumnName = rsmd.getColumnName(1);

            // collect column names 2 through n in a list
            ArrayList<String> columnNames = new ArrayList<String>();
            for (int i = 2; i <= rsmd.getColumnCount(); i++) {
                columnNames.add(rsmd.getColumnName(i));
            }

            // "unpivot" the raw data into [myTable]
            st.execute("DELETE FROM myTable");
            for (String columnName : columnNames) {
                st.execute(
                        "INSERT INTO [myTable] (" +
                                "[observed], " +
                                "[objectName], " +
                                "[measurement] " +
                            ") " +
                        "SELECT " +
                            "[" + timeStampColumnName + "], " +
                            "'" + columnName + "', " +
                            "[" + columnName + "] " +
                        "FROM [excelImport]");
            }

            st.close();
            con.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

}

[myTable] 中的结果数据如下所示:

observed             objectName  measurement
-------------------  ----------  -----------
2013-03-10 01:00:00  Object1             1.1
2013-03-10 01:00:00  Object2             1.2
2013-03-10 01:00:00  Object3             1.3
2013-03-10 02:00:00  Object1             2.1
2013-03-10 02:00:00  Object2             2.2
2013-03-10 02:00:00  Object3             2.3
2013-03-10 03:00:00  Object1             3.1
2013-03-10 03:00:00  Object2             3.2
2013-03-10 03:00:00  Object3             3.3

【讨论】:

  • 感谢您的回答。不幸的是,这并不能解决我的问题,因为我不仅将数据从 Excel 复制到 Access,而且还更改了格式。我的输入是一个 n 时间 m 表,而 n 是时间戳的数量,m 是每个时间戳具有测量数据的对象的数量。但在我的数据库中,它应该生成一个 (n*m) 乘以 3 的表,其中每个条目看起来像“Date, Measured_by, Value”
  • @DCircle 你的 Excel 数据看起来像 this 吗?
  • 没错!在我的数据库中,它应该看起来像您的第一个屏幕截图,只是在“someText”和“someDateTime”上设置了主键,而 someText 将是测量站的 ID。
  • 我用我的数据库和 excel 工作表尝试了你的代码,但我得到了这个错误:java.sql.SQLException: [Microsoft][ODBC Microsoft Access Driver]Allgemeiner Fehler Registrierungsschlüssel 'Temporary (volatile) Jet DSN for process 0x1d34 Thread 0x2754 DBC 0x2e64fbc Jet' kann nicht geöffnet werden. 它说上面提到的注册表项无法打开。抱歉,我对 odbc 驱动程序有点缺乏经验。我需要先以某种方式“注册”Jet 驱动程序吗?
  • @DCircle 我不时看到该错误,通常是在我对表结构进行了一些更改或编辑了其他一些数据库对象之后。我要做的第一件事是完全关闭 Access,然后再次尝试运行我的 Java 代码。
猜你喜欢
  • 2013-05-06
  • 2012-05-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-05
相关资源
最近更新 更多