Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Paginação baseada em cursor MySQL com várias colunas


Se (a infelizmente nomeada) coluna Column_1 é único, você poderia apenas fazer:
 WHERE Column_1 > :last_retrieved_value

Pela pergunta, parece que Column_1 não é exclusivo, mas o (Column_1,Column_2) tupla é única.

A forma geral para uma consulta "próxima página", ordenando por essas duas colunas, usando os últimos valores recuperados para essas duas colunas, seria...
    (Column1,Column2) > (:lrv_col1,:lrv_col2)

(lrv =valor salvo da última linha recuperada pela consulta anterior)

Para escrever essa condição no MySQL, podemos fazer isso como você mostrou:
 WHERE t.Column_1 > :lrv_col1
    OR ( t.Column_1 = :lrv_col1 AND t.Column_2 > :lrv_col2 )

Ou poderíamos escrever assim, o que eu prefiro, porque há muito menos chance de o MySQL ficar confuso com a condição OR e usar o índice errado...
 WHERE t.Column_1 >= :lrv_col1
       AND ( t.Column_1 > :lrv_col1 OR t.Column_2 > :lrv_col2 )
 ORDER BY t.Column_1, t.Column_2
 LIMIT n

Para estender isso para três colunas, para verificar a condição...
  (c1,c2,c3) > (:lrv1,:lrv2,:lrv3)

Nós lidamos com isso como no caso de duas colunas, manipulando c1 primeiro, dividindo-o como as duas colunas:
 WHERE c1 >= :lrv1
       AND ( c1 > :lrv1 OR ( ... ) )
 ORDER BY c1, c2, c3
 LIMIT n

E agora esse espaço reservado ... (onde teria apenas a verificação em c2 antes, é realmente mais um caso de duas colunas. Precisamos verificar:(c2,c3) > (lrv2,lrv3) , para que possamos expandir isso usando o mesmo padrão:
 WHERE c1 >= :lrv1
       AND ( c1 > :lrv1 OR ( c2 >= :lrv2 
                             AND ( c2 > :lrv2 OR c3 > :lrv3 )
                           )
           )
 ORDER BY c1,c2,c3
 LIMIT n

Concordo que a expansão pode parecer um pouco confusa. Mas segue um padrão muito regular. Da mesma forma, poderíamos expressar a condição em quatro colunas...
 (c1,c2,c3,c4) > (:lrv1,:lrv2,:lrv3,:lrv4)

Apenas pegamos o que temos para as três colunas e precisamos expandir c3 > :lrv3 para substituí-lo por ( c3 >= :lrv3 AND ( c3 > :lrv3 OR c4 > :lrv4 ) )
 WHERE c1 >= :lrv1
       AND ( c1 > :lrv1 OR ( c2 >= :lrv2 
                             AND ( c2 > :lrv2 OR ( c3 >= :lrv3
                                                   AND ( c3 > :lrv3 OR c4 > :lrv4 )
                                                 )
                                 )
                           )
           )
 ORDER BY c1,c2,c3,c4
 LIMIT n

Como auxílio ao futuro leitor, comentaria este bloco, e indicaria a intenção...
 -- (c1,c2,c3,c4) > (lr1,lr2,lr3,lr4)

E seria bom se o MySQL nos permitisse expressar a comparação assim. Infelizmente, temos que expandir isso para algo que o MySQL entenda.