簡體   English   中英

如何使用Joins將分頁應用於SQL查詢的結果?

[英]How to apply pagination to the result of a SQL query with Joins?

我有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結果的數量(即,因為客戶端將顯示為他們擁有的帳戶類型數量的多倍,LIMIT不會應用客戶端數量,但客戶端數量* accountTypes,這不是我想要的)。

我想出的唯一解決方案是從查詢中刪除LIMIT(和OFFSET,因為這也是錯誤的)並以編程方式應用它們:

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支持它,請使用窗口函數DENSE_RANK 例如:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM