2011-07-14 14 views
2

フィルタリング(開始文字、カテゴリなど)を使用するときにCodeigniter(IMHO)完全に機能し、働いています - 私は2つのクエリを実行していると彼らの間の唯一の違いは、彼らの最後にLIMIT(とOFFSET)があることです。 この2番目のクエリは、行の総数を取得する必要があり、LIMITを持つため、「メイン」クエリで取得できないため、限られた行数を返すため、この2番目のクエリが必要です。Codeigniter + MySql:ページング時に二重クエリを避けるためにCOUNTをこのクエリに統合します。

QUERY 1( "メイン" の問合せ)

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(この1つは、行をカウント)

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について何かを読んで私はそれを完全に不慣れだと、また多くはそれだけでまれに使用されなければならないので、それがデータベースに追加負担をかけることを言うので、それを実装couldntの。

ご協力いただければ幸いです!

+0

正確には、2番目のステートメント(つまり、 '$ noLimit')を使って何をしようとしていますか?あなたはすべての行を取得しようとしているのですか、すべてのアーティストや曲の合計ですか?あなたがやるべきことに応じて、パフォーマンス上の問題の可能性にかかわらず*保守性*のために2つのクエリとして残す方がよいでしょう。 –

+0

$ noLimitには、最後にLIMITがないときのクエリのレコード数が含まれていることに注意してください。想像してみましょう:あなたはすべてのアーティストや曲を表示したいと思っていますし、ジャンルやファーストレターなどで絞り込んだりしたりしないかもしれません。一度に1ページあたりのレコード数を定義することができます。したがって、私は$ noLimitの行を数え、それを$ total_recordsとしてページ分割に使用し、$ perLimitレコードも$ per_page configを定義する項目としてページ分割スクリプトに送信することにしました – developer10

+0

私に何か提案があればこれは簡単です、私はそれを聞きたいです! – developer10

答えて

2

あなたは(unpaginated)行の総数得るためにこのような何かを行うことができます:

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; 

最初のサブクエリがちょうどあなたがアーティストを検索するために提供しました条件を使用していますがそれらの条件を満たす行(アーティスト)の合計を数えます。これらのアーティストがこのサブクエリに曲を持っているかどうかは関係ありませんので、JOIN_tbl_songsの表は必要ありません。

関連する問題