Неизвестное количество знаков подстановки (?) в preparedStatement

У меня есть некая форма с checkbox. Например нужно выбрать кол-во комнат в номере отеля. Если 4 чекбокса, то соответственно первый чекбокс - одна комната в номере, второй - две комнаты и т.д. Я хочу получить все подходящие комнаты из базы данных. Для этого использую preparedStatement, код получится что-то типо:

PreparedStatement ps = null;
        try (Connection con = dbManager.getConnection()) {
            String sql = <<<here my sql>>>
            ps = con.prepareStatement(sql);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            try {
                if (ps != null) {
                    ps.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }

Но я заранее не знаю сколько чекбоксов отметит пользователь. Если отметит 2, то надо будет SELECT * FROM room WHERE number_of_beds = ? or ?;

А если 4, то SELECT * FROM room WHERE number_of_beds = ? or ? or ? or ?;

Как можно вместо ? подставить массив? Или только через циклы и StringBuilder или простую конкатенацию создавать sql?


Ответы (1 шт):

Автор решения: Roman Konoval

К сожалению в jdbc нет переносимого (т.е. такого, чтоб работал с любой БД) способа передать список значений как одну переменную.

Из доступных опций:

  1. генерировать запрос с помощью StringBuilder или чего то подобного. Обратите внимание, что в вопросе у вас ошибка в синтаксисе. Нужно или number_of_beds = ? or number_of_beds = ? or number_of_beds = ? или number_of_beds in (?, ?, ?).
  2. выполнять запрос в цикле для каждого значения параметра. В этом случае нужно использовать PreparedStament, чтоб быстрей работало, но на каждый запрос все равно будет отдельный вызов по сети.
  3. использовать хранимую процедуру, которая уже на стороне БД сделает этот цикл. Тут мы экономим на вызовах по сети, но привязываемся к конкретной БД.

Для postgres есть вариант с одним параметром. Можно создать массив и его передать:

statement.setArray(1, connection.createArrayOf("integer", numberOfBedsList));

В условии запроса нужно использовать условие number_of_beds = ANY(?).

→ Ссылка