Динамическое заполнение SQL в Java из массива с нулями
Чтобы дать простой пример моей проблемы:
//Create database table allowing nulls.
CREATE TABLE test(one int not null, two int null, three int not null);
Теперь в Java у меня есть массив объектов, соответствующих содержимому базы данных. Мне нужно создать оператор вставки / обновления / удаления для этой таблицы базы данных, используя значения массива.
Object[] arr = { 4, null, 1 };
String sql = GenereateInsert(arr);
Это становится трудным, хотя, потому что мне нужно пропустить пустые поля из вставки заранее. Например, если два выше не является нулем:
INSERT INTO test(4, 2, 1);
все легко Но если оно пустое, мне нужно следующее:
INSERT INTO test(one, three) values(4, 1);
Таблицы, с которыми я имею дело, имеют размер 50 столбцов и выше, поэтому я не хочу делать это вручную, это будет неуправляемо. Итак, как люди решают эту проблему в целом? Это должна быть обычная ситуация.
PS: я не хочу использовать полную библиотеку ORM, это кажется излишним.
3 ответа
Я хотел бы предложить что-то вроде этого:
Запустите запрос как
SELECT * FROM <TABLE_NAME> LIMIT 1
, ИспользоватьResultSetMetaData
чтобы получить columnNames и их columnType. Сохраните его в HashMap, а ключи в ArrayList.Теперь создайте
PreparedStatement
используя ключи из ArrayList в качестве columnNames. Я думаю, что это не будет трудно сделатьТеперь, учитывая ваши данные в массиве, тот факт, что вы знаете, какой тип SQL они представляют из HashMap, вы можете легко использовать эту информацию для отображения значений, которые вы получаете из своего массива в
?
вашего сгенерированного PreparedStatement.
Теперь вопрос в том, как бороться с null
, Хорошо, так как вы знаете тип столбца, если полученное значение null
тогда вы можете использовать PreparedStatement.setNull(...)
установить их как ноль.
Кроме того, просто хотел отметить, что согласно этому документу, есть важное руководство по setXXX(...) JDBC:
6.1.5 Отправка JDBC NULL в качестве параметра IN
Метод setNull позволяет программисту отправлять значение JDBC NULL (универсальный SQL NULL) в базу данных в качестве параметра IN. Обратите внимание, однако, что все еще необходимо указать тип JDBC параметра.
JDBC NULL также будет отправлено в базу данных, когда нулевое значение Java передается методу setXXX (если он принимает объекты Java в качестве аргументов). Однако метод setObject может принимать нулевое значение только в том случае, если указан тип JDBC.
Это будет означать, что вы можете отправить пустое значение в качестве значения параметра вашего setXX(...)
метод, и вы действительно не должны вызывать setNull(..)
метод явно.
Я надеюсь, что это работает для вас!
Алгоритм высокого уровня:
- Сохранить массив имен столбцов (в том же порядке, что и входные параметры) - давайте назовем это
allColumnNames
- как поле класса. - Когда метод вызывается, создайте два новых, пустых
List<String>
s, один для представления имен столбцов, один для представления значений - давайте назовем ихcolumnNamesList
а такжеcolumnValuesList
, - Выполните итерацию по входному массиву, для каждого ненулевого элемента добавьте
allColumnNames[i]
вcolumnNamesList
а такжеvalues[i]
кcolumnValuesList
, - Создайте свой оператор вставки путем объединения
INSERT INTO tablename
, разделенный запятыми список каждого из значений вcolumnNames
,VALUES
и разделенный запятыми список каждого из значений вcolumnValuesList
,
Не уверен насчет других систем баз данных, но в postgres вы можете вставить нулевое значение следующим образом:
CREATE TABLE test(
id SERIAL PRIMARY KEY,
val1 INTEGER DEFAULT NULL,
val2 INTEGER DEFAULT NULL,
val3 INTEGER DEFAULT NULL
);
INSERT INTO test(val1, val2, val3) VALUES(DEFAULT, DEFAULT, DEFAULT);
Вы также можете сделать операторы set таким же образом:
UPDATE test SET val1 = DEFAULT, val2 = 123, val3 = DEFAULT WHERE id = 3;
Таким образом,
Stringbuilder sqlStmt = new StringBuilder();
sqlStmt.append("INSERT INTO test(val1, val2, val3) VALUES(");
sqlStmt.append(((val1 == null) ? "DEFAULT" : val1.toString()));
sqlStmt.append(" , ");
sqlStmt.append(((val2 == null) ? "DEFAULT" : val2.toString()));
sqlStmt.append(" , ");
sqlStmt.append(((val3 == null) ? "DEFAULT" : val3.toString()));
sqlStmt.append(";");
statement.execute(sqlStmt.toString());
Если у вас их много, возможно, имеет смысл сделать это с циклом for-each.