Я проверяю Apache Derby, он же JavaDB. Кажется, я не могу обойти повторяющиеся ключевые проблемы при вставке записей, которые, возможно, уже существуют. Есть ли в Дерби эквивалент «insert if not exists» или «merge»?
Точно так же есть способ сделать что-нибудь вроде "drop table foo if exists"?




Я никогда не использовал apache derby, но общее решение, которое практически не зависит от базы данных, выглядит следующим образом:
Чтобы вставить значения 'a' и 'b' в таблицу foo (со столбцами с именами A, B), но только там, где значений еще нет, попробуйте что-то вроде
INSERT INTO foo (
SELECT 'a' as A, 'b' as B
FROM foo
WHERE
A = 'a' AND B = 'b'
HAVING count(*)=0
)
Это может потребовать настройки для конкретной базы данных, но идея состоит в том, чтобы вставить результат выбора, который возвращает только значения, когда их нет.
Это полезный прием для создания идемпотентного сценария sql (который ничего не делает при втором запуске). Однако будьте осторожны при использовании этого в производственном коде, поскольку HAVING count(*)=0 может быть очень медленным на больших таблицах.
Хороший трюк. Можно ли заставить его работать с несколькими строками? Возможно, используя синтаксис VALUES, но я не уверен.
Работает также для HSQLDB! Очень хорошо!
На самом деле использование MERGE намного лучше; посмотрите этот ответ: stackoverflow.com/questions/2609996/…
Это вызывает Error code 0, SQL state XJ001: Java exception: '8: java.lang.ArrayIndexOutOfBoundsException'. при использовании в качестве партии.
Стандартный способ, который я использовал с базами данных PostgreSQL, выглядит примерно так:
INSERT INTO foo ( col1, col2, col3, ... )
SELECT 'col1 value', 'col2 value', 'colc value', ...
WHERE NOT EXISTS (
SELECT 0
FROM foo
WHERE col1 = 'col1 value'
...
)
Не уверен, насколько он портативен или строго соответствует ANSI. Отсутствие предложения FROM во внешнем операторе SELECT может быть нестандартным. Но попробуйте.
Для этого нет встроенной поддержки, чтобы обойти это, я использую eclipse-link, eclipse-link будет пытаться создать таблицы и игнорировать любые ошибки, возникающие при попытке создать таблицы, которые уже существуют.
Если вы вносите изменения в схему, вы можете указать eclipse link, чтобы удалить таблицы перед их созданием.
Я использую это решение, но вы должны использовать его, только если понимаете разницу между дубликат из представления базы данных и дубликат из пользовательского представления
Дубликаты из пользовательского представления - это две записи со всеми идентичными полями.
while (ResultSet.next()) {
try {
PreparedStatement insertion = myConn.prepareStatement("insert into table values (?)");
insertion .setString(1, "test");
insertion .executeUpdate();
} catch (SQLException e) {
if (e.getSQLState().equals("23505"))//Found duplicate from database view
{continue;}//ignore duplicate and continue with the insert statement
else{try {
throw e;
} catch (Exception ex) {
}
}
}
}
Разве вторая попытка не гарантирует, что ничего никогда не будет брошено? По сути, весь блок catch (SQLException) будет вести себя точно так же, как если бы он был полностью пуст.
Запрос на поддержку оператора MERGE SQL: 2003 регистрируется в системе отслеживания ошибок Derby как https://issues.apache.org/jira/browse/DERBY-3155.
Вы можете проголосовать за эту проблему или, что еще лучше, внести свой вклад в реализацию!
В противном случае единственные известные мне решения требуют либо сначала выбрать строку, чтобы увидеть, существует ли она, либо вставить ее и перехватить исключение, как отмечали другие.
Вы можете упаковать эту логику в процедуру базы данных, чтобы упростить ее выполнение.
Уф. SQL: 2003 MERGE ужасен. Стандартный и гибкий, но столько текста, чтобы вставить строку!
Я согласен ... так много дублирования (то же самое касается классического трюка выше). Интересно, есть ли стандартная альтернатива, потому что, если бы я нашел ее в то время, я бы попросил ее вместо этого.
У меня была такая же проблема, и я получил ее для вставки только с одним значением / столбцом в Derby. (Я никогда не собирался тестировать его с другими, но у меня нет причин предполагать, что этого не должно быть):
INSERT INTO my_table (my_column)
(SELECT 'new_value_to_insert'
FROM my_table
WHERE my_column = 'new_value_to_insert'
HAVING count(*)=0)
Идеально! Я знаю, что это разные базы данных, чем вопрос, но это решение работает для меня с PostgreSQL и HSQLDB.
Дерби реализовал MERGE в 10.11: https://db.apache.org/derby/docs/10.11/ref/rrefsqljmerge.html
Обратите внимание, что вам необходимо обновить вашу БД до 10.11 перед ее использованием: https://db.apache.org/derby/docs/10.11/devguide/cdevupgrades.html
Если вы не привязаны к Дерби, попробуйте H2 - это Быстрее, и в нем есть очень красивый и простой глагол ОБЪЕДИНЕНИЕ.