Вот проблема: в моей компании есть большая база данных, в которой мы хотим выполнить некоторые автоматизированные операции. Чтобы проверить это, мы получили небольшую выборку этих данных о 6 CSM-файлах размером 10 МБ. Мы хотим использовать H2, чтобы проверить результаты нашей программы в нем. H2, похоже, отлично работал с нашими предыдущими cvs, хотя они были не более 1000 записей. Когда дело доходит до любого из наших файлов размером 10 МБ, команда
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 я могу обнаружить, что реестр не дублируется, поскольку столбец datetime уникален во всем наборе данных.
Я не могу предоставить эти данные для проверки, поскольку компания продает эту информацию. Но вот как выглядит мое определение таблицы.
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();
}
Я буду рад предоставить дополнительную информацию, если потребуется.
EDIT
@ Рэнди Я всегда проверяю, чиста ли база данных перед запуском команды, и в моей Java-программе у меня есть процедура удаления всех данных из файла, который не может быть вставлен.
select * from myschema.mytable where largenumber = 25485116;
DATETIME LARGENUMBER VALUE FLAG KIND
(no rows, 8 ms)