Codeigniter + MySql: интегрируйте COUNT в этот запрос, чтобы избежать двойных запросов при разбивке на страницы - PullRequest
2 голосов
/ 14 июля 2011

Поскольку для нумерации страниц в Codeigniter (IMHO) не хватает некоторых полезных вещей для более легкой реализации при использовании фильтров (начальная буква, категория и т. Д.), Даже несмотря на то, что моя нумерация страниц полностью функциональна и работает - у меня работает два запроса, и единственное различие междуони в том, что у одного из них есть LIMIT (и OFFSET) в конце.Этот второй запрос необходим, потому что мне нужно получить общее количество строк, и с моим «основным» запросом я не могу его получить, поскольку он имеет LIMIT, поэтому он возвращает ограниченное количество строк.

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 (этот счетчик подсчитывает строки)

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

Код модели (это грязно, я знаю :)):

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;
}

Так что мне на самом деле нужно, вместо того, чтобы эти 2 сложных запроса выполнялись, я бы предпочел сделать один запрос, даже если он станет более сложным, но я хочу получить из него общее количество строк.

Я что-то прочитало sql_calc_found_rows, но не смог реализовать его, потому что я совершенно незнаком с ним, а также многие говорят, что это создает дополнительную нагрузку на базу данных, поэтому ее следует использовать только в редких случаях.

Любая помощь будет оценена!

1 Ответ

2 голосов
/ 22 августа 2012

Вы можете сделать что-то вроде этого, чтобы получить общее количество (не разбитых на страницы) строк:

( См. Вывод по 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;

В первом подзапросе используются только те условия, которые вы указали для поиска исполнителей, и подсчитывается общее количество строк (исполнителей), соответствующих этим условиям. Нам не нужно JOIN к таблице _tbl_songs здесь, так как нам все равно, есть ли у этих исполнителей какие-либо песни в этом подзапросе.

...