OOP pagination & PDO/SQL

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Mark L

Mark L

10/06/2010 13:25:23
Quote Anchor link
Ik ben bezig om een pagination class te maken.
Ik ben nu bezig met een pagination class die de results uit een database haalt. In het verleden heb ik een pagination-functie geschreven en toen haalde ik het AANTAL results gewoon d.m.v. het uitvoeren van de SQL en dan m.b.v. mysql_num_rows() het aantal results bepalen.
Ik ben er achter gekomen dat dit traag kan zijn, als er VEEL results zijn. Nu dacht ik: ik verander de SQL met een 'COUNT(*) AS paginationCount' erbij. Hierdoor komt er maar één result binnen die het aantal result bevat: precies wat ik nodig heb. Het aantal results heb ik nodig om het aantal pagina's te bepalen.

Dus bij het aanmaken van de class, geef je een SQL-statement mee (uiteraard een SELECT-SQL-statement). Deze word dan aangepast met 'COUNT(*) AS paginationCount'.

Ik gebruik voor het eerst PDO en vroeg me af of hier toevallig een betere optie voor is. Zo niet, vroeg ik me af of ik dit veilig kan gebruiken:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
<?php
preg_match('#^SELECT (.*?) FROM (.*?)$#is', $sql, $match);
$count_sql = 'SELECT '.$match[1].', COUNT(*) AS paginationCount FROM '.$match[2];
?>


Het werkt bij de tests die ik heb uitgevoerd, maar ik was benieuwd naar jullie mening. Vergeet ik niet iets?

Voorbeeld:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
<?php
$sql
= 'SELECT name, id, face FROM users'; // Zo gaat hij erin
$count_sql = 'SELECT name, id, face, COUNT(*) AS paginationCount FROM users'; // Zo komt hij eruit
?>


Dus eigenlijk de vragen die ik hierover heb zijn:
- Is hier een betere manier voor?
- Zo niet, is dit veilig te gebruiken (werkt dit bij elk indenkbaar SQL-scenario?)

Alvast bedankt,
Mark L.
Gewijzigd op 10/06/2010 13:32:09 door Mark L
 
PHP hulp

PHP hulp

22/11/2024 21:59:41
 
Pim -

Pim -

10/06/2010 14:31:03
Quote Anchor link
Je kan mijns inziens geen SQL string met een functie om gaan gooien. Op deze manier maak je wat complexere queries ook onmogelijk. Wat je beter kan doen is in de functie zelf de SQL opbouwen, dus gewoon de te selecteren velden en het tabel als argument meegeven aan de functie. Nog wat beter is een querybuilder te gebruiken, een klasse die die query voor je aanmaakt.
Iets als: http://www.phpclasses.org/package/2813-PHP-Dynamically-build-SQL-queries.html

Wanneer je gebruik maakt van de genoemde klasse krijg je iets als:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
<?php
function paginate($table, array $fields = array('*'), $start = 0, $pageCount = 10, $order = null) {
    $sql = new SqlQueryBuilder('select');
    $sql->setTable($table);
    foreach($fields as $field) $sql->addColumn($field);
    if(!is_null($order)) $sql->setOrderBy($order);
    $sql->setLimit($start . ', '. $start + $pageCount;
    return $sql->buildQuery();
}

?>
Gewijzigd op 10/06/2010 14:33:28 door Pim -
 
Jelmer -

Jelmer -

10/06/2010 22:47:24
Quote Anchor link
Met Oracle gebruikte ik een soort window. Gooide gewoon de hele query in het FROM deel van een COUNT query, zodat hij het aantal resultaten telde, en daarna datzelfde trucje maar dan met ROWCOUNT om een aantal van die resultaten daadwerkelijk op te halen. (Die Oracle die ik gebruikte kende geen LIMIT...OFFSET...)

Misschien werkt zoiets ook goed met MySQL:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php

class PaginatedResultSet
{
    private $query, $pageSize, $page;
    
    public function __construct($query, $pageSize = 60, $page = 0)
    {

        $this->query = $query;
        
        $this->pageSize = $pageSize;
        
        $this->page = $page;
    }

    
    public function count()
    {

        $result = mysql_query(sprintf('SELECT COUNT(*) FROM (%s)', $this->query));
        
        return $result
            ? mysql_result($result, 0)
            :
false;
    }

    
    public function fetchAll()
    {

        $result = mysql_query(sprintf('SELECT * FROM (%s) LIMIT %d OFFSET %d',
            $this->query, $this->pageSize, $this->page * $this->pageSize));
        
        if(!$result)
            return false;
        
        $rows = array();
        
        while($row = mysql_fetch_assoc($result))
            $rows[] = $row;
        
        return $rows;
    }
}

?>
Gewijzigd op 10/06/2010 22:49:05 door Jelmer -
 
Mark L

Mark L

12/06/2010 12:03:26
Quote Anchor link
Bedankt Jelmer. Het duurde even voordat ik begreep wat het deed (2 dagen xD) maar ik begrijp het. Jammer genoeg werkt het niet, op mySQL.
Bedankt Pim, maar ik schrijf liever mijn querys dan dat ik ze laat genereren.
Maar nu ben ik op het idee VIEWs gekomen; ik was gewoon even mijn kennis over SQL aan 't vergroten, toen ik hierop stuitte. Nu kan ik niet echt een duidelijk beeld krijgen van VIEWs en hoe ik deze goed of slecht kan gebruiken.
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
<?php
$createview
= 'CREATE VIEW paginationView AS '.$sql; // Create view
$query = 'SELECT COUNT(*) AS paginationCount FROM paginationView'; // Pak aantal van de view
$deleteview = 'DROP VIEW paginationView'; // Delete view
?>


Ik heb nog nooit met VIEWs gewerkt, en ik denk dat ik het eigenlijk verkeerd gebruik. Volgens mij moet een VIEW alleen gebruikt worden als je hier langer dan één query mee wil werken. Wat zijn de voor- en nadelen van deze aanpak? Kan ik voor mijn doel VIEWs gebruiken, of toch beter niet?

Alvast bedankt,
Mark
Gewijzigd op 12/06/2010 12:05:40 door Mark L
 
Noppes Homeland

Noppes Homeland

12/06/2010 12:33:22
Quote Anchor link
Een view creeer je in principe maar 1 keer, dus CREATE en DROP hoort niet thuis in de procedurele code.

Als je de views goed weet op te bouwen en te gebruiken dan heeft vele voordelen.

SELECT * is zo ie zo al niet duidelijk en vaak haal je dan ook data op waarmee je niets doet. Benoem dus gewoon de velden waarin de data staat waarmee je iets gaat doen.

In feite kan je simpelweg dit doen:

SELECT u.name
, u.id
, u.face
, pc.paginationCount
FROM users U
, (SELECT COUNT(*) paginationCount
FROM users) pc


en als je er dan kijkt naar view
1ste view wordt dan
SELECT u.name
, u.id
, u.face
FROM users u

2de view wordt dan
SELECT COUNT(*) paginationCount
FROM users

3de view
SELECT u.name
, u.id
, u.face
, pc.paginationCount
FROM usersvw u
, pageingcountvw pc


uiteraad kan je ook 1 view maken
SELECT u.name
, u.id
, u.face
, pc.paginationCount
FROM users U
, (SELECT COUNT(*) paginationCount
FROM users) pc

Mijn voorkeur gaat dan uit naar de 3 views, want die views kan je dan ook nog gebruiken om andere views samen te stellen

Nadeel views in mysql speciale aandacht nodig hebben, je zult altijd met explain moeten blijven kijken voor optimalisatie, dus dan kan het zijn dat je een tijdje kwijt bent met zoeken welke view niet goed in elkaar steekt als je views nest.
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.