2011-02-03 83 views
1

這是問題:在我的公司,我們有一個大型數據庫,我們希望在其中執行一些自動操作。爲了測試我們獲得了關於6個10MB大小的csv文件的小數據樣本。我們想用H2來測試我們程序的結果。 H2儘管他們最多隻有1000個參賽作品,但看起來和我們以前的cvs一起工作得很好。當涉及到我們的任何10MB的文件命令未能將大型數據集加載到h2數據庫中

insert into myschema.mytable (select * from csvread('mycsvfile.csv')); 

報告失敗,因爲註冊表中的一個假想複製和冒犯我們的主鍵約束。

Unique index or primary key violation: "PRIMARY_KEY_6 ON MYSCHEMA.MYTABLE(DATETIME, LARGENUMBER, KIND)"; SQL statement: 
insert into myschema.mytable (select * from csvread('src/test/resources/h2/data/mycsvfile.csv')) [23001-148] 23001/23001 

打破mycsvfile.csv成小塊,我能看到問題開始(儘管數量取決於什麼數據我不同而不同)後插入約10000行出現。但是,如果我將文件分解爲多個部分,然後單獨運行該命令,我可以插入超過10000行。但即使我設法手動插入所有數據,我需要一個自動方法來填充數據庫。

由於運行該命令不會給我導致問題的行我猜想問題可能是在csvread例程中的某個緩存。

然後我創建了一個小型的java程序,可以手動將數據插入到H2數據庫中。無論我是否批量執行命令,關閉並打開1000行h2的連接都會報告我試圖複製數據庫中的條目。

org.h2.jdbc.JdbcSQLException: Unique index or primary key violation: "PRIMARY_KEY_6 ON MYSCHEMA.MYTABLE(DATETIME, LARGENUMBER, KIND)"; SQL statement: 
INSERT INTO myschema.mytable VALUES ('1997-10-06 01:00:00.0',25485116,1.600,0,18) [23001-148] 

做了使用Emacs我能找到註冊表中沒有重複的日期時間列註冊表中的一個正常的搜索是在整個數據集是唯一的。

由於公司銷售該信息,我無法給您提供該數據供您測試。但這裏是我的表定義是如何。

create table myschema.mytable (
    datetime timestamp, 
    largenumber numeric(8,0) references myschema.largenumber(largecode), 
    value numeric(8,3) not null, 
    flag numeric(1,0) references myschema.flag(flagcode), 
    kind smallint references myschema.kind(kindcode), 
    primary key (datetime, largenumber, kind) 
); 

這是我們的CSV的樣子:

datetime,largenumber,value,flag,kind 
1997-06-11 16:45:00.0,25485116,0.710,0,18 
1997-06-11 17:00:00.0,25485116,0.000,0,18 
1997-06-11 17:15:00.0,25485116,0.000,0,18 
1997-06-11 17:30:00.0,25485116,0.000,0,18 

和Java代碼,將填補我們的測試數據庫(原諒我的醜陋的代碼,我絕望:)

private static void insertFile(MyFile file) throws SQLException { 
    int updateCount = 0; 
    ResultSet rs = Csv.getInstance().read(file.toString(), null, null); 
    ResultSetMetaData meta = rs.getMetaData(); 
    Connection conn = DriverManager.getConnection(
      "jdbc:h2:tcp://localhost/mytestdatabase", "sa", "pass"); 
    rs.next(); 
    while (rs.next()) { 
     Statement stmt = conn.createStatement(); 
     StringBuilder sb = new StringBuilder(); 
     for (int i = 0; i < meta.getColumnCount(); i++) { 
      if (i == 0) 
       sb.append("'" + rs.getString(i + 1) + "'"); 
      else 
       sb.append(rs.getString(i + 1)); 
      sb.append(','); 
     } 
     updateCount++; 
     if (sb.length() > 0) 
      sb.deleteCharAt(sb.length() - 1); 

     stmt.execute(String.format(
       "INSERT INTO myschema.mydatabase VALUES (%s) ", 
       sb.toString())); 
     if (updateCount == 1000) { 
      conn.close(); 
      conn = DriverManager.getConnection(
        "jdbc:h2:tcp://localhost/mytestdatabase", "sa", "pass"); 
      updateCount = 0; 
     } 
    } 
    if (!conn.isClosed()) { 
     conn.close(); 
    } 
    rs.close(); 
} 

如果有要求,我很樂意提供更多信息。

編輯

@Randy我總是檢查如果數據庫是運行命令之前,在我的java程序我有一個程序來從失敗中插入一個文件刪除所有數據乾淨。

select * from myschema.mytable where largenumber = 25485116; 
DATETIME LARGENUMBER  VALUE FLAG KIND 
(no rows, 8 ms) 
+1

也許你可以添加一些調試打印輸出到你的java代碼來指定導致失敗的確切行。然後,將數據庫(而不是源文件)轉換爲現有記錄。也許你正在獲取日期時間截斷? – Randy 2011-02-03 19:27:21

回答

0

我能想到的唯一的事情就是在表格上有一個觸發器,將時間戳設置爲「now」。雖然這並不能解釋爲什麼你只有幾行成功,但它可以解釋爲什麼主鍵被違反。