Java 如何对带有联接的SQL查询的结果应用分页?
我有一个SQL查询,它连接3个表,其中一个是连接其他两个表的多对多查询。我使用Spring JDBC ResultSetTextRactor将ResultSet转换为大致如下所示的对象:Java 如何对带有联接的SQL查询的结果应用分页?,java,sql,postgresql,jdbc,Java,Sql,Postgresql,Jdbc,我有一个SQL查询,它连接3个表,其中一个是连接其他两个表的多对多查询。我使用Spring JDBC ResultSetTextRactor将ResultSet转换为大致如下所示的对象: class Customer { private String id; private Set<AccountType> accountTypes; ... } public List<Client> extractData(ResultSet rs) thro
class Customer {
private String id;
private Set<AccountType> accountTypes;
...
}
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());
}
但是,由于此查询具有联接,当我限制结果的数量时,我实际上是在限制联接结果的数量,即,由于客户机的出现次数与其拥有的帐户类型的数量相同,因此该限制不是应用于客户机的数量,而是应用于客户机的数量*帐户类型,这不是我想要的
我提出的唯一解决方案是删除限制和偏移量,因为这在查询中也是错误的,并以编程方式应用它们:
List<Client> allClients = jdbcTemplate.query....
List<Client> result = allClients.subList(offset, offset+limit);
但这显然不是一个非常好、有效的解决方案。有更好的方法吗?有趣的是,写一个问题能让你思考,而且实际上能帮助你为自己的问题想出解决方案 我可以通过简单地将查询的分页部分添加到主查询的子查询而不是主查询本身来解决这个问题 例如,不要执行以下操作:
SELECT client.id, client.name ...
FROM clients AS client
LEFT JOIN client_account_types AS cat ON client.id = cat.client_id
FULL JOIN account_types AS at ON cat.account_type_id = at.id
ORDER BY client.name ASC
LIMIT 10 OFFSET 30;
我正在这样做:
SELECT client.id, client.name ...
FROM (
SELECT * FROM clients
ORDER BY name ASC
LIMIT 10 OFFSET 0
) AS client
LEFT JOIN client_account_types AS cat ON client.id = cat.client_id
FULL JOIN account_types AS at ON cat.account_type_id = at.id;
希望这对其他人也有帮助。如果您的DBMS支持,请使用窗口功能。例如:
SELECT ... ORDER BY name ASC LIMIT 10 OFFSET 30;
SELECT * FROM
(SELECT *, DENSE_RANK() OVER (ORDER BY name, id) count FROM
(SELECT a.id, a.name, b.title, DENSE_RANK() OVER (ORDER BY a.name, a.id) offset_
FROM AUTHOR a, BOOK b
WHERE a.id = b.authorId) result_offset
WHERE offset_ > 30) result_offset_count
WHERE count <= 10
Renato,在三个表联接上创建一个视图,然后使用ORDER BY name ASC LIMIT 10 OFFSET 30;从视图中选择*的技术\u名称?由您的DBA运行此命令,看看他们是否乐意允许此操作。@Rob Kielty-感谢您的建议。。。我会尝试一下,看看是否比我刚刚发布的解决方案更有效。测试是一条路要走。如果您有一位DBA维护数据库,他们应该会很高兴您向他们咨询每种方法的优缺点。我正在努力解决同一个问题,但还没有弄清楚这个查询是如何解决问题的。如果客户机要求页面大小为10,那么它希望得到10个客户机,其中每个客户机有N个帐户类型等等。因此,您最多只能获得10行或少于10行,如果任何客户机有多个帐户类型,您最终返回的帐户将少于10行。