开发者

Codeigniter+MySql: Integrate COUNT into this query to avoid double queries when paginating

开发者 https://www.devze.com 2023-03-20 15:06 出处:网络
Since pagination in Codeigniter (IMHO) lack some good stuff for easier implementation when using filters (beginning letter, category, etc.), even though my pagination is fully functional and working -

Since pagination in Codeigniter (IMHO) lack some good stuff for easier implementation when using filters (beginning letter, category, etc.), even though my pagination is fully functional and working - i have two queries running and the only difference between them is that one of them has LIMIT (and OFFSET) at the end. This second query is needed because i have to get the total number of rows and with my "main" query i can't get it because it has LIMIT so it returns limited number of rows.

QUERY 1 ("main" query)

SELECT art.*, songs.numsongs 
        FROM _tbl_artists AS art
 开发者_开发问答       LEFT JOIN 
        (SELECT _ARTIST_ID, COUNT(*) AS numsongs 
        FROM _tbl_songs GROUP BY _ARTIST_ID) AS songs 
        ON art._ID_ORIGINAL = songs._ARTIST_ID 
        WHERE art._artist_type = 0 AND art._ARTIST_NAME LIKE 'C%' AND art.id > 0 ORDER BY art._ARTIST_NAME ASC LIMIT 20, 20

QUERY 2 (this one counts rows)

SELECT art.*, songs.numsongs 
        FROM _tbl_artists AS art
        LEFT JOIN 
        (SELECT _ARTIST_ID, COUNT(*) AS numsongs 
        FROM _tbl_songs GROUP BY _ARTIST_ID) AS songs 
        ON art._ID_ORIGINAL = songs._ARTIST_ID 
        WHERE art._artist_type = 0 AND art._ARTIST_NAME LIKE 'C%' AND art.id > 0 ORDER BY art._ARTIST_NAME ASC

Model code (it's messy, i know :) ):

function loadArtists($type='', $letter='', $uriOffset=0, $perPage='')
{
    $letterEval = preg_match('[0-9]', $letter);
    switch($letterEval):
        case 1:
            $operator = 'REGEXP';
            $letter = "^[0-9]";
            $s = '';
            break;
        case 0:
            $operator = 'LIKE';
            $letter = "$letter";
            $s = '%';
            break;
        default: 0; break;
    endswitch;

    $query = "SELECT SQL_CALC_FOUND_ROWS art.*, songs.numsongs 
        FROM _tbl_artists AS art
        LEFT JOIN 
        (SELECT _ARTIST_ID, COUNT(*) AS numsongs 
        FROM _tbl_songs GROUP BY _ARTIST_ID) AS songs 
        ON art._ID_ORIGINAL = songs._ARTIST_ID 
        WHERE";
        if($type == 0 || $type == 1)
            $query .= " art._artist_type = $type AND";

        if($letter != '')
            $query .= " art._ARTIST_NAME $operator '$letter$s' AND";
        else
            $query .= '';

    $query .= " art.id > 0 ORDER BY art._ARTIST_NAME ASC";

    if ($uriOffset != '')
        $limited = $query . " LIMIT $uriOffset, $perPage";
    else
        $limited = $query . " LIMIT $perPage";

    $noLimit = $this->db->query($query);
    $withLimit = $this->db->query($limited);

    $numRows = $withLimit->num_rows(); 

    $resultStack = array();
    $resultStack = array($numRows);


    if($withLimit->num_rows() > 0)
    {
        $result = $withLimit->result();
        $message = '';
    }

    else
    {
        $result = NULL;
        $message = 'Nema rezultata';
    }

    array_push($resultStack, $result, $message);

    return $resultStack; //$resultStack;
}

So what i actually need is, instead of having these 2 complicated queries running, i'd rather make one query even if it get more complicated but i want to get total rows count from it.

I read something about sql_calc_found_rows but couldnt implement it because i'm totally unfamiliar with it and also many say that it puts additional strain to the database so it should be used only in rare cases.

Any help will be appreciated!


You could do something like this to obtain the total number of (unpaginated) rows:

(See the output on SQL Fiddle)

SELECT art.*, songs.numsongs, artist_count.total
    FROM _tbl_artists AS art
    JOIN (
        SELECT COUNT(*) as total
        FROM _tbl_artists as art
        WHERE art._artist_type = 0
        AND art._ARTIST_NAME LIKE 'C%' AND art.id > 0
    ) artist_count
    LEFT JOIN (
        SELECT _ARTIST_ID, COUNT(*) AS numsongs 
        FROM _tbl_songs GROUP BY _ARTIST_ID
    ) AS songs ON art._ID_ORIGINAL = songs._ARTIST_ID 
    WHERE art._artist_type = 0
    AND art._ARTIST_NAME LIKE 'C%' AND art.id > 0
    ORDER BY art._ARTIST_NAME ASC
    LIMIT 20, 20;

The first subquery just uses the conditions you've provided for searching for artists and counts the total rows (artists) that meet those conditions. We don't need to JOIN to the _tbl_songs table here as we don't care whether these artists have any songs in this subquery.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号