2012-01-26 15 views
1

私は比較的複雑なクエリである(私の限られMYSQLの知識を持つ)ものを持っている:このクエリに多対多のテーブルのリレーションシップを追加する

$sQuery = " 
     SELECT SQL_CALC_FOUND_ROWS 
    songsID, song_name, artist_band_name, author, song_artwork, song_file, 
    song_description, uploaded_time, emotion, tempo, 
    user, happiness, instruments, similar_artists, play_count, 
    projects_count, 
    rating, ratings_count, waveform, datasize, display_name, user_url, 
    IF(user_ratings_count, 'User Voted', 'Not Voted') as voted 
FROM (
     SELECT 
      sp.songsID, projects_count, 
      AVG(rating) as rating, 
      COUNT(rating) AS ratings_count, 
      COUNT(IF(userid=$userid, 1, NULL)) as user_ratings_count 

       FROM (
        SELECT songsID, COUNT(*) as projects_count 
        FROM $sTable s 
        LEFT JOIN $sTable2 p ON s.songsID = p.songs_id 

        GROUP BY songsID) as sp 

      LEFT JOIN $sTable3 r ON sp.songsID = r.songid 

      GROUP BY sp.songsID) as spr 


JOIN $sTable s USING (songsID) 
LEFT JOIN $sTable5 q ON s.user = q.ID 


     $sWhere 
     $sOrder 
     $sLimit 

このクエリは、5から与えられた曲に関するすべての情報を取得します異なるテーブル。

変数$ sWhereはクエリのWHERE部分を作成し、ユーザーの入力に基づいてこの曲のリストを動的にフィルタ可能にするためにサーバーに送信されるデータに依存します。

$ sOrderと$ sLimitを注文し、ユーザーの入力に基づいて結果を再度制限します。

ジャンルのリスト(wp_genres)を含むこの式に6番目のテーブルを追加する必要があります。このテーブルは$ sTableのsongsIDカラムにリンクテーブル(wp_song_genres)を介して次の構造でリンクされています。

$sTable(wp_songs) $sTable6(wp_genre_songs)  $sTable7(wp_genres) 
songsID*    song_id*      genre_id** 
column2    genre_id**     genre_name 
column3           icon_url 
column4 
column5 
etc... 

アスタリスクはリンクを表します。

私がする必要があるのは、曲の結果の動的フィルタがジャンル別に曲のリストをフィルタリングできるようにすることですが、新しいテーブルを導入する方法を考えることはできません($ sTable6と$ sTable7)をクエリに追加します。

この部分は「SSEARCH」を介して受け取ったテキストを取り、任意の一致するテキストの列を検索します。

以下は私のクエリのWHEREの部分を生成するコードです。ユーザが入力最小テンポ値と(フォント端にjqueryの範囲スライダを介して行われる)最大テンポ値できるよう

$sWhere = ""; 
if ($_GET['sSearch'] != "") 
{ 
    $aWords = preg_split('/\s+/', $_GET['sSearch']); 
    $sWhere = "WHERE ("; 

    for ($j=0 ; $j<count($aWords) ; $j++) 
    { 
     if ($aWords[$j] != "") 
     { 
      $sWhere .= "("; 
      for ($i=0 ; $i<count($aColumns) ; $i++) 
      { 
       $sWhere .= $aColumns[$i]." LIKE '%".mysql_real_escape_string($aWords[$j])."%' OR "; 
      } 
      $sWhere = substr_replace($sWhere, "", -3); 
      $sWhere .= ") AND "; 
     } 
    } 
    $sWhere = substr_replace($sWhere, "", -4); 
    $sWhere .= ')'; 
} 

この部分は、「範囲」フィルタです。データはsSearch_ *を介して受信されます。

/* Individual column filtering */ 
for ($i=0 ; $i<count($aColumns) ; $i++) 
{ 
    if ($_GET['bSearchable_'.$i] == "true" && $_GET['sSearch_'.$i] != '') 
    { 
     if ($sWhere == "") 
     { 
      $sWhere = "WHERE "; 
     } 
     else 
     { 
      $sWhere .= " AND "; 
     } 







     $columnFilterValue = mysql_real_escape_string($_GET['sSearch_' . $i]); 
     // check for values range 
     $rangeSeparator = "~"; 
     if (!empty($rangeSeparator) && strstr($columnFilterValue, $rangeSeparator)) { 
      // get min and max 

      $columnFilterRangeMatches = explode('~', $columnFilterValue); 

      // get filter 
      if (empty($columnFilterRangeMatches[0]) && empty($columnFilterRangeMatches[1])) 
       $sWhere .= " 0 = 0 "; 
      else if (!empty($columnFilterRangeMatches[0]) && !empty($columnFilterRangeMatches[1])) 
       $sWhere .= $aColumns[$i] . " BETWEEN '" . $columnFilterRangeMatches[0] . "' and '" . $columnFilterRangeMatches[1] . "' "; 
      else if (empty($columnFilterRangeMatches[0]) && !empty($columnFilterRangeMatches[1])) 
       $sWhere .= $aColumns[$i] . " < '" . $columnFilterRangeMatches[1] . "' "; 
      else if (!empty($columnFilterRangeMatches[0]) && empty($columnFilterRangeMatches[1])) 
       $sWhere .= $aColumns[$i] . " > '" . $columnFilterRangeMatches[0] . "' "; 
     } else { 
      $sWhere .= $aColumns[$i] . " LIKE '%" . $columnFilterValue . "%' "; 
     } 
    } 
} 

genre_idのデータはsSearch_23経由で入力されます。つまり、$ _GET ['SSearch ']に結果をフィルタリングするgenre_idが含まれます。多くのジャンルタグの結果を一緒に追加する必要があることに注意してください。

ユーザーがジャンルを選択した場合:rock(genre_id:1)$ sTableのgenre_id:1が関連付けられているすべての曲が返されます。 (現在のクエリで検索された曲に関する残りの情報と一緒に)

しかし、ユーザーがジャンルを選択した場合:rock(genre_id:1)ANDジャンル:pop(genre_id:2)AND genenre:rap

私はこのような複雑な質問であり、私はそれをうまく表現していない可能性があることを私は謝ります。私の現在のコードに関係なく、私は本当に誰かが私を助けることができるか、または私に正しい方向に少なくともpintを願っています。

多くのありがとう!

編集:私はちょうど私のクエリにfollingを追加することによって、「ほとんどの仕事に彼を得るためにanagedいる

LEFT JOIN (
      SELECT igs.song_id, igs.genre_id, g.genre_name 
      FROM $sTable6 AS igs 
      JOIN wp_genres AS g 
      ON igs.genre_id = g.genre_id 
      ) as gs 
      ON songsID = gs.song_id   

だから、全体のことは今見えることのように: -

$sQuery = " 
     SELECT SQL_CALC_FOUND_ROWS 
    songsID, song_name, artist_band_name, author, song_artwork, song_file, 
    genre, song_description, uploaded_time, emotion, tempo, 
    user, happiness, instruments, similar_artists, play_count, 
    projects_count, 
    rating, ratings_count, waveform, datasize, display_name, user_url, genre_id, 
    IF(user_ratings_count, 'User Voted', 'Not Voted') as voted 
FROM (
     SELECT 
      sp.songsID, projects_count, 
      AVG(rating) as rating, 
      COUNT(rating) AS ratings_count, 
      COUNT(IF(userid=$userid, 1, NULL)) as user_ratings_count 

       FROM (
        SELECT songsID, COUNT(*) as projects_count 
        FROM $sTable s 
        LEFT JOIN $sTable2 p ON s.songsID = p.songs_id 

        GROUP BY songsID) as sp 

      LEFT JOIN $sTable3 r ON sp.songsID = r.songid 





      GROUP BY sp.songsID) as spr 

LEFT JOIN (
      SELECT igs.song_id, igs.genre_id, g.genre_name 
      FROM $sTable6 AS igs 
      JOIN wp_genres AS g 
      ON igs.genre_id = g.genre_id 
      ) as gs 
      ON songsID = gs.song_id   



JOIN $sTable s USING (songsID) 
LEFT JOIN $sTable5 q ON s.user = q.ID 





     $sWhere 
     $sOrder 
     $sLimit 

genre_idによるクエリは、現在、完全に動的に行われます。しかし、クエリのWHERE部分にgenre_idが指定されていない場合、私は行を二重にしています。曲/ジャンルのリンクテーブルにエントリを持つ各曲が複製されます。

まず、私の現在の解決策は、最適化/ベストプラクティスという点で優れた解決策ですか?次に、これらの重複行をどのようにして防ぐことができますか?

注:リンクテーブルの両方の列に一意のプライマリキーが既にあります。

答えて

1

http://hackmysql.com/case4 これは、あなたのデータベースが膨大な量の行に到達する可能性があることを考慮すると、これは良い読書として役立つと思います。あなたのmysqlテーブルでインデックスキーを使用すると、あるテーブルが別のテーブルから描画されなければならないクエリや、あるテーブルに類似の値を持ち、これは、少なくとも私の知る限り、テーブル全体をスキャンする必要がなくなります。

+0

幻想的な読書のように見えます。私はあなたにそれを投稿する時間を割いてくれて非常に感謝しています。これは非常に便利です。それは私の質問に答えるのではなく、非常に感謝しています。乾杯! :-) – gordyr