Paginação com SQL Server 2008 R2 no PHP

Basicamente podemos executar uma determinada consulta envolvendo ou não várias tabelas e utilizar esses registros para diversas finalidades, inclusive utilizando recursividade de consultas. Dentro desse contexto ainda vamos usar ROW_NUMBER() em conjunto com a clausula OVER().
ROW_NUMBER(): Retorna o número sequencial de uma linha em uma partição de um conjunto de resultados, iniciando em 1 para a primeira linha de cada partição.
OVER(): Determina o particionamento e a ordenação de um conjunto de linhas antes da aplicação da função de janela associada. Isto é, clausula OVER define uma janela ou conjunto de linhas especificado pelo usuário em um conjunto de resultados de consulta. Uma função de janela computa um valor cada linha na janela.
Com essas informações básicas fica mais fácil de entender como será escrita a instrução de paginação, a ideia é escrever um SELECT usando CTE onde serão retornados os dados da tabela artigos e o número da linha usando ROW_NUMBER(). A partir desse CTE poderemos limitar a quantidade de registros e também definir qual o intervalo de registros que vamos exibir.
Exemplo:
1 2 3 4 |
WITH Paginado AS (SELECT ROW_NUMBER() OVER(ORDER BY id ASC) AS linha, id, titulo FROM artigos) SELECT Paginado WHERE linha > QTDE_REGISTROS * (PAGINA_ATUAL - 1) |
Agora que já sabemos basicamente como funcionam CTEs, ROW_NUMBER() e OVER(), é hora de por a mão na massa criando o banco de dados, tabela e inserindo os dados fictícios.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
CREATE DATABASE blog GO USE blog GO CREATE TABLE `artigos` ( id INT IDENTITY PRIMARY KEY, titulo varchar(100), autor varchar(100), previa varchar(200), data date ) |
1 2 3 |
INSERT INTO artigos(titulo, autor, previa, data)VALUES('Paginação com SQL Server 2008', 'João', 'Paginação sobre SQL Server 2008 publicada ...', getDate()) GO 35 |
Criando script de paginação com SQL Server
index.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
<?php /* Constantes de configuração */ define('QTDE_REGISTROS', 5); define('RANGE_PAGINAS', 1); /* Recebe o número da página via parâmetro na URL */ $pagina_atual = (isset($_GET['page']) && is_numeric($_GET['page'])) ? $_GET['page'] : 1; /* Cria uma conexão PDO com SQL Server */ $pdo = new PDO("sqlsrv:host=localhost; database=blog;", "usuario", "123456"); /* Instrução de consulta para paginação com SQL Server */ $sql = "WITH Paginado AS "; $sql .= "(SELECT ROW_NUMBER() OVER(ORDER BY id ASC) AS linha, id, titulo, autor, previa, CONVERT(VARCHAR(10), data, 103) AS data FROM artigos)"; $sql .= "SELECT TOP (".QTDE_REGISTROS.") id, titulo, autor, previa, data "; $sql .= "FROM Paginado "; $sql .= "WHERE linha > ".QTDE_REGISTROS." * ({$pagina_atual} - 1)"; $stm = $pdo->prepare($sql); $stm->execute(); $dados = $stm->fetchAll(PDO::FETCH_OBJ); /* Conta quantos registos existem na tabela */ $sqlContador = "SELECT COUNT(*) AS total_registros FROM artigos"; $stm = $pdo->prepare($sqlContador); $stm->execute(); $valor = $stm->fetch(PDO::FETCH_OBJ); /* Idêntifica a primeira página */ $primeira_pagina = 1; /* Cálcula qual será a última página */ $ultima_pagina = ceil($valor->total_registros / QTDE_REGISTROS); /* Cálcula qual será a página anterior em relação a página atual em exibição */ $pagina_anterior = ($pagina_atual > 1) ? $pagina_atual -1 : ; /* Cálcula qual será a pŕoxima página em relação a página atual em exibição */ $proxima_pagina = ($pagina_atual < $ultima_pagina) ? $pagina_atual +1 : ; /* Cálcula qual será a página inicial do nosso range */ $range_inicial = (($pagina_atual - RANGE_PAGINAS) >= 1) ? $pagina_atual - RANGE_PAGINAS : 1 ; /* Cálcula qual será a página final do nosso range */ $range_final = (($pagina_atual + RANGE_PAGINAS) <= $ultima_pagina ) ? $pagina_atual + RANGE_PAGINAS : $ultima_pagina ; /* Verifica se vai exibir o botão "Primeiro" e "Pŕoximo" */ $exibir_botao_inicio = ($range_inicial < $pagina_atual) ? 'mostrar' : 'esconder'; /* Verifica se vai exibir o botão "Anterior" e "Último" */ $exibir_botao_final = ($range_final > $pagina_atual) ? 'mostrar' : 'esconder'; ?> <!DOCTYPE html> <html> <head> <meta charset='utf-8'> <title>Paginação - William Programação</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css"> <link rel="stylesheet" href="css/estilo.css"> </head> <body> <div class='container'> <div class="row"> <h1 class="text-center">Paginação de Dados</h1><hr> <?php if (!empty($dados)): ?> <table class="table table-striped table-bordered"> <thead> <tr class='active'> <th>Código</th> <th>Título</th> <th>Autor</th> <th>Prévia</th> <th>Data</th> </tr> </thead> <tbody> <?php foreach($dados as $artigo):?> <tr> <td><?=$artigo->id?></td> <td><?=$artigo->titulo?></td> <td><?=$artigo->autor?></td> <td><?=$artigo->previa?></td> <td><?=$artigo->data?></td> </tr> <?php endforeach; ?> </tbody> </table> <div class='box-paginacao'> <a class='box-navegacao <?=$exibir_botao_inicio?>' href="index.php?page=<?=$primeira_pagina?>" title="Primeira Página">Primeira</a> <a class='box-navegacao <?=$exibir_botao_inicio?>' href="index.php?page=<?=$pagina_anterior?>" title="Página Anterior">Anterior</a> <?php /* Loop para montar a páginação central com os números */ for ($i=$range_inicial; $i <= $range_final; $i++): $destaque = ($i == $pagina_atual) ? 'destaque' : '' ; ?> <a class='box-numero <?=$destaque?>' href="index.php?page=<?=$i?>"><?=$i?></a> <?php endfor; ?> <a class='box-navegacao <?=$exibir_botao_final?>' href="index.php?page=<?=$proxima_pagina?>" title="Próxima Página">Próxima</a> <a class='box-navegacao <?=$exibir_botao_final?>' href="index.php?page=<?=$ultima_pagina?>" title="Última Página">Último</a> </div> <?php else: ?> <p class="bg-danger">Nenhum registro foi encontrado!</p> <?php endif; ?> </div> </div> </body> </html> |
Observação: A folha de estilo CSS foi postado no artigo Paginação de Dados no PHP com PDO – Introdução.
O script está bem comentado, mas vou explicar os pontos que considero chave para que funcione a paginação da maneira que planejamos. Nesse e nos outros artigos poderemos observar que a sintaxe PDO para consulta será idêntica para todos os SGBDs, isso porque essa biblioteca abstrai todas as particularidades de cada SGBD.
1 2 3 |
/* Constantes de configuração */ define('QTDE_REGISTROS', 5); define('RANGE_PAGINAS', 1); |
1 2 |
/* Recebe o número da página via parâmetro na URL */ $pagina_atual = (isset($_GET['page']) && is_numeric($_GET['page'])) ? $_GET['page'] : 1; |
1 2 3 4 5 |
$sql = "WITH Paginado AS "; $sql .= "(SELECT ROW_NUMBER() OVER(ORDER BY id ASC) AS linha, id, titulo, autor, previa, CONVERT(VARCHAR(10), data, 103) AS data FROM artigos)"; $sql .= "SELECT TOP (".QTDE_REGISTROS.") id, titulo, autor, previa, data "; $sql .= "FROM Paginado "; $sql .= "WHERE linha > ".QTDE_REGISTROS." * ({$pagina_atual} - 1)"; |
1 2 3 4 5 |
/* Conta quantos registos existem na tabela */ $sqlContador = "SELECT COUNT(*) AS total_registros FROM artigos"; $stm = $pdo->prepare($sqlContador); $stm->execute(); $valor = $stm->fetch(PDO::FETCH_OBJ); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* Idêntifica a primeira página */ $primeira_pagina = 1; /* Cálcula qual será a última página */ $ultima_pagina = ceil($valor->total_registros / QTDE_REGISTROS); /* Cálcula qual será a página anterior em relação a página atual em exibição */ $pagina_anterior = ($pagina_atual > 1) ? $pagina_atual -1 : ; /* Cálcula qual será a pŕoxima página em relação a página atual em exibição */ $proxima_pagina = ($pagina_atual < $ultima_pagina) ? $pagina_atual +1 : ; /* Cálcula qual será a página inicial do nosso range */ $range_inicial = (($pagina_atual - RANGE_PAGINAS) >= 1) ? $pagina_atual - RANGE_PAGINAS : 1 ; /* Cálcula qual será a página final do nosso range */ $range_final = (($pagina_atual + RANGE_PAGINAS) <= $ultima_pagina ) ? $pagina_atual + RANGE_PAGINAS : $ultima_pagina ; |
1 2 |
/* Verifica se vai exibir o botão "Primeira" e "Anterior" */ $exibir_botao_inicio = ($range_inicial < $pagina_atual) ? 'mostrar' : 'esconder'; |
1 2 |
/* Verifica se vai exibir o botão "Próxima" e "Última" */ $exibir_botao_final = ($range_final > $pagina_atual) ? 'mostrar' : 'esconder'; |
Bom pessoal, neste artigo demonstrei como construir uma paginação com SQL Server, assim chegamos ao final dessa série de artigos sobre paginação de dados, é evidente que existem diversas maneiras de se montar esse layout de paginação, com variações de CSS, HTML e lógica PHP. Na internet existem diversos plugins para esse tipo de funcionalidade, os principais frameworks para PHP possuem métodos para isso, mas antes de usar soluções prontas é interessante saber como funciona, quais as limitações do SGBD que você está usando em seu projeto para se trabalhar com paginação.
Espero que tenha gostado, até a próxima …