С помощью приведенного ниже кода я могу вставить несколько записей в базу данных H2. Но с Oracle это не работает. Есть ли другой способ использовать обычный SQL для INSERT нескольких подобных операторов.
//INSERT RECORDS
String sql = "INSERT INTO PERSON (NAME, AGE) VALUES ('"+name+"',+"+age+");" +
"INSERT INTO PERSON (NAME, AGE) VALUES ('Susan' ,20 )";
Statement statement = connection.createStatement();
int success = statement.executeUpdate(sql);
Почему нет. Если эти значения не получены из внешнего интерфейса, опасности от SQL-инъекции нет. И ReadedStatement должен делать то же самое => генерировать правильный INSERT. Также этот код предназначен для обучения. Я пытаюсь понять пакетную вставку, и у меня сложилось впечатление, что она создаст строку, подобную этой, с большим количеством INSERT. Но это не работает с Oracle.
Это просто хорошая практика, и нет необходимости рисковать, что цитирование пойдет не так. Кроме того, в противном случае вы не сможете получить никакой потенциальной оптимизации от использования переменных связывания. Пакетная обработка имеет другую цель — она предназначена для оптимизации записи, а не для выполнения того, что по сути является запуском сценария SQL. Я бы посмотрел, «как запустить SQL-скрипт в JDBC?»
"Почему нет." Некоторые драйверы+серверы могут использовать кэшированные проанализированные операторы/планы выполнения. При конкатенации каждый оператор уникален, поэтому повторное использование не требуется. Это не проблема для небольших партий, но может существенно изменить ситуацию в крупных корпоративных системах.
Подготовленное утверждение также ускользает: Если у вас имя с апострофом 'd'Isle'
. Если вы попробуете два оператора одновременно, VALUES((...), (...)) поможет. Но ReadedStatements просто полезны. Неиспользование их помечает инструменты или читателей-людей.
один Statement
может содержать только один оператор - даже использование ;
в конце поддерживается/не всеми драйверами
@user85421 Хотя это верно для операторов SQL, в Oracle вы также можете использовать один оператор PL/SQL, и этот один оператор PL/SQL может содержать несколько операторов SQL (каждый из которых должен заканчиваться знаком ;
, как и оператор PL/SQL; однако терминатор оператора /
для блока PL/SQL запрещен). Таким образом, ОП мог бы использовать BEGIN INSERT INTO PERSON (NAME, AGE) VALUES ('Alice',20); INSERT INTO PERSON (NAME, AGE) VALUES ('Susan', 20); END;
(но, вероятно, лучше использовать параметризованный запрос и пакетные вставки).
@MT0 ну, PL/SQL — это не Java; и один оператор (PL/)SQL, даже если он содержит больше операторов, все равно остается одним оператором; и вопрос заключается не в использовании оператора PL/SQL, а в двух операторах - это SQL-клиент Oracle, который интерпретирует ;
как разделитель операторов - и, кстати, это был один из старых JDBC (не PL/SQL). SQL) драйверы именно Oracle, которые не допускали точку с запятой в конце (одного) оператора.
Используйте ReadedStatement и не включайте терминатор ;
в оператор SQL (поскольку он не является частью оператора SQL и не является допустимым синтаксисом):
connection con.setAutoCommit(false);
PreparedStatement ps=connection.prepareStatement(
"INSERT INTO PERSON (NAME, AGE) VALUES (?,?)"
);
ps.setString(1, "Susan");
ps.setInt(2, 20);
ps.addBatch();
ps.setString(1, "Alice");
ps.setInt(2, 21);
ps.addBatch();
int [] numInserts = ps.executeBatch();
connection.commit();
Примечание. В Oracle в команде не может быть более одного оператора, поэтому попытка передать INSERT INTO t VALUES('X'); INSERT INTO t VALUES('Y')
завершится синтаксической ошибкой, даже если операторы синтаксически действительны по отдельности (это помогает предотвратить атаки SQL-инъекцией). Вам необходимо либо (1) отправить их по отдельности как две команды, либо (2) обернуть их в блок PL/SQL, чтобы они стали одной командой. В вашем случае просто используйте пакет операторов.
Есть ли другой способ использовать обычный SQL для нескольких подобных операторов?
Существует несколько способов вставить несколько строк в один оператор:
Используя оператор INSERT
:
INSERT ALL
INTO person (name, age) VALUES ('Susan', 20)
INTO person (name, age) VALUES ('Alice', 21)
SELECT 1 FROM DUAL
Используя INSERT ALL
:
INSERT INTO person (name, age)
SELECT 'Susan', 20 FROM DUAL UNION ALL
SELECT 'Alice', 21 FROM DUAL
Ответ Мурейника показывает, как использовать INSERT INTO ... SELECT ...
с несколькими предложениями INSERT INTO
, которое доступно в Oracle 23.
Использование PL/SQL для переноса нескольких отдельных VALUES
:
BEGIN
INSERT INTO person (name, age) VALUES ('Susan', 20);
INSERT INTO person (name, age) VALUES ('Alice', 21);
END;
Вы можете параметризовать все эти запросы, заменив INSERT
, 'Susan'
, 'Alice'
и 20
на 21
, а затем передать значения в качестве параметров привязки с помощью Java.
Примечание. Первые три не включают завершающий ?
, но решение PL/SQL будет включать завершающий ;
для завершения оператора ;
(но не завершающий END
в качестве терминатора для блока PL/SQL).
Ответ MTO об использовании пакетов, вероятно, лучший способ.
Сказав это, просто чтобы дать полную картину исходного вопроса:
Есть ли другой способ использовать обычный SQL для INSERT нескольких подобных операторов.
В Oracle (начиная с версии 23) вы можете иметь несколько наборов values
с запятыми (,
) между ними:
String SQL = "INSERT INTO PERSON (NAME, AGE) VALUES ('"+name+"',+"+age+"), ('Susan', 20)";
Это, конечно, можно сделать с помощью PreparedStatement
и связать значения вместо их объединения:
String SQL = "INSERT INTO PERSON (NAME, AGE) VALUES (?, ?), ('Susan', 20)";
PreparedStatement ps = connection.prepareStatement(SQL);
ps.setString(1, name);
ps.setInt(2, age);
ps.executeUpdate();
или даже преобразовать все значения в заполнители:
String SQL = "INSERT INTO PERSON (NAME, AGE) VALUES (?, ?), (?, ?)";
PreparedStatement ps = connection.prepareStatement(SQL);
ps.setString(1, name);
ps.setInt(2, age);
ps.setString(3, "Susan");
ps.setInt(4, 20);
ps.executeUpdate();
«В Oracle вы можете иметь несколько наборов значений с запятыми (,) между ними». Только из Oracle 23, до этого вам нужно было использовать оператор INSERT ALL
или INSERT ... SELECT ... FROM DUAL UNION ALL SELECT .... FROM DUAL
. См. этот вопрос.
@MT0 хорошее отличие, спасибо — отредактировал это.
Вам определенно не следует передавать такие параметры. Используйте
PreparedStatement
сsetX
"INSERT INTO PERSON (NAME, AGE) VALUES (?, ?)"