Apache Derby: как я могу "вставить, если не существует"?
Я даю Apache Derby, aka JavaDB спин. Кажется, что я не вижу дублирующих ключевых проблем при вставке записей, которые могут уже существовать. Существует ли Derby эквивалентно "insert if not exists
" или "merge
"?
Аналогично, есть ли способ сделать что-то вроде "drop table foo if exists
"?
Ответы
Ответ 1
Я никогда не использовал 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
)
Это может потребовать настройки для определенных dbms, но идея состоит в том, чтобы вставить результат выбора, который возвращает только значения, когда есть не.
Это полезный трюк для создания idempotent sql script (тот, который ничего не делает во второй раз, когда он выполняется). Однако будьте осторожны при использовании этого в производственном коде, поскольку HAVING count(*)=0
может быть очень медленным на больших таблицах.
Ответ 2
Запрос на поддержку оператора SQL: 2003 MERGE записывается в трекер ошибок Derby как https://issues.apache.org/jira/browse/DERBY-3155
Вы можете проголосовать за эту проблему или, что еще лучше, внести вклад в реализацию!
В противном случае единственные решения, о которых я знаю, требуют либо сначала выбрать строку, чтобы увидеть, существует ли она, либо вставить ее, либо перехватить исключение, как отмечали другие.
Вы можете упаковать эту логику в процедуру базы данных, чтобы сделать ее несколько проще выполнить.
Ответ 3
Стандартный способ, который я использовал с базами данных 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 может быть нестандартным. Дайте ему хотя бы.
Ответ 4
Derby внедрил 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
Ответ 5
У меня была та же проблема, и я получил эту работу для вставки только с одним значением/столбцом в 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)
Ответ 6
Для этого нет встроенной поддержки, чтобы обойти его. Я использую eclipse-link, eclipse-link будет пытаться создавать таблицы и игнорировать любые ошибки, возникающие при попытке создать уже существующие таблицы.
Если вы внесете изменения схемы, вы можете указать ссылку eclipse, чтобы удалить таблицы перед их созданием.
Ответ 7
Я использую это решение, но вы должны использовать его, только если вы понимаете разницу между дубликатом из представления базы данных и дубликата из пользовательского представления
- Дубликаты из представления базы данных представляют собой две записи с одним и тем же основным ключом
-
Дубликаты из представления пользователя представляют собой две записи со всеми идентичными файлами
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) {
}
}
}
}