Как применить разбиение на страницы к результату SQL-запроса с помощью соединений?

У меня есть SQL-запрос, который соединяет 3 таблицы, одна из которых представляет собой просто «многие ко многим», соединяющая две другие. Я использую Spring JDBC ResultSetExtractor для преобразования ResultSet в мои объекты, которые выглядят примерно так:

class Customer {
    private String id;
    private Set<AccountType> accountTypes;
    ...
}

Реализация ResultSetExtractor выглядит так:

public List<Client> extractData(ResultSet rs) throws SQLException,
    DataAccessException {
        Map<Integer, Client> clientsMap = new LinkedHashMap<Integer, Client>();
        while (rs.next()) {
            int id = rs.getInt("id");
            // add the client to the map only the first time
            if (!clientsMap.containsKey(id)) {
                Client client = new Client();
                client.setId(id);
                ...
                clientsMap.put(id, client);
            }
            // always add the account type to the existing client
            Client client = clientsMap.get(id);
            client.addAccountType(extractAccountTypeFrom(rs, id));
        }
        return new ArrayList<Client>(clientsMap.values());
}

Это прекрасно работает без нумерации страниц.

Однако мне нужно разбить эти результаты на страницы. Я обычно делаю это, добавляя это к запросу, например:

SELECT ... ORDER BY name ASC LIMIT 10 OFFSET 30;

Однако, поскольку этот запрос имеет соединения, когда я ограничиваю количество результатов, я фактически ограничиваю количество результатов JOINED (т.е. как client будет появляться столько раз, сколько у него типов учетных записей, LIMIT применяется не к количеству клиентов, а к количеству client*accountTypes, а это не то, что мне нужно).

Единственное решение, которое я придумал, состояло в том, чтобы удалить LIMIT (и OFFSET, потому что это тоже было бы неправильно) из запроса и применить их программно:

List<Client> allClients = jdbcTemplate.query....
List<Client> result = allClients.subList(offset, offset+limit);

Но это явно не очень хорошее и эффективное решение. Есть ли лучший способ?

5
задан Renato 11 June 2012 в 00:07
поделиться