2016-08-31 16 views
1

私は2つのテーブル:activitytagを持っています。 1つのactivityには多くのものがあります。tags現在の設定を最適化して、テーブル内のすべてのアクティビティを見つけて、すべてのタグを見つけるために各アクティビティを繰り返し実行する必要があります。最後に、コンテンツをJSONとして処理します。だから、私たちの最終的なコードは、そのような何かに見える1対多の結果に1つのクエリを設定する

-- Query that we execute one time 
SELECT `id`, `name` 
FROM `activity` 

-- Query that we execute N times 
SELECT `id`, `name`, `color` 
FROM `tag` 
WHERE `tag`.`activityId` = $activityId 

:ここ

は一例であり

$result = mysqli_query(" 
    SELECT `id`, `name` 
    FROM `activity` 
"); 

$data = array(); 

for ($i=0; $i<mysqli_num_rows($result); $i++) { 
    $row = mysqli_fetch_assoc($result); 

    $data[$i]["activityId"] = $row["id"]; 
    $data[$i]["name"] = $row["name"]; 
    $data[$i]["tags"] = array(); 

    $activityId = $row["id"]; 

    $resultTags = mysqli_query(" 
     SELECT `id`, `name`, `color` 
     FROM `tag` 
     WHERE `tag`.`activityId` = $activityId 
    "); 

    for ($j=0; $j<mysqli_num_rows($resultTags); $j++) { 
     $row = mysqli_fetch_assoc($resultTags); 

     $data[$i]["tags"][$j]["name"] = $row["name"]; 
     $data[$i]["tags"][$j]["color"] = $row["color"]; 
    } 
} 

PS:これは私たちのクエリとテーブルが道より複雑で、擬似コードです、それは基本的に私たちの問題の本質です。

これは、内部クエリを使用すること、またはそれ以上に、結合だけで達成することは可能ですか?

5つのテーブルを作成する必要があるため、私たちはそれぞれのアクティビティに対して5つのクエリを実行してしまいます。

ありがとうございます。

答えて

0

確か活動テーブルの上にちょうどJOINタグテーブル。

クエリは次のようになります。

SELECT activity.id, activity.name, tag.name AS tagName, tag.color AS tagColor 
FROM activity 
JOIN tag ON tag.activityId = activity.id; 

アクティビティテーブルの主キーがidで、各行が(すなわち、名前は任意のactivity.idのために変更されることはありません)一意であること、そしてインクルードが何のタグが存在しない場合でも、安全で登録しようという考え。少なくともN行を返します。Ntag.activityId行の番号で、対応するidの行はactivityになります。

PHPでは、このように1つのクエリで配列を構築できます。

$data = []; 
foreach($result as $row) { 

    $tags = ["name" => $row["tagName"], "color" => $row["tagColor"]]; 

    if (isset($data[$row["id"]])) { 
     $data[$row["id"]]["tags"][] = $tags; 
    } else { 
     $data[$row["id"]] = [ 
      [ 
       "id" => $row["id"], 
       "name" => $row["name"], 
       "tags" => [$tags], 
      ], 
     ]; 
    } 

} 

活動テーブル内の情報は変更されることはありませんので、我々は追加する必要がある唯一のものは、我々がループ内isset($data[$row["id"]])をチェックすることによって行うれ、タグです。

したがって、SQLFiddleでは、activityに4行、tagテーブルに6行がある2つのテーブルの実例を見ることができます。これにより合計6行が得られます。アクティビティ表のIDの1つにタグがないため、結果セットから除外されます。 0個のタグを含む行を返すには、like thisの代わりにLEFT JOINを使用できます。

SELECT activity.id, activity.name, 
     tag.activityId AS tagId, tag.name AS tagName, tag.color AS tagColor 
FROM activity 
LEFT JOIN tag ON tag.activityId = activity.id; 

これは、空のタグ行に対してNULL値を取得することを意味します。 PHPをこのように変更することができます。

$data = []; 
foreach($result as $row) { 

    $tags = empty($row["tagId"]) ?: ["name" => $row["tagName"], "color" => $row["tagColor"]]; 

    if (isset($data[$row["id"]]) && $tags) { 
     $data[$row["id"]]["tags"][] = $tags; 
    } else { 
     $data[$row["id"]] = [ 
      [ 
       "id" => $row["id"], 
       "name" => $row["name"], 
       "tags" => $tags ? [$tags] : [], 
      ], 
     ]; 
    } 

} 

のでjson_encodeを使用してPHPからあなたの最終的出力は、SQLFiddleのサンプルデータと、このようになるはずです。

 
    "1": { 
     "id": 1, 
     "name": "foo", 
     "tags": [ 
      { 
       "tagName": "tag-a", 
       "tagColor": "red" 
      }, 
      { 
       "tagName": "tag-b", 
       "tagColor": "green" 
      }, 
      { 
       "tagName": "tag-c", 
       "tagColor": "blue" 
      } 
     ] 
    }, 
    "2": { 
     "id": 2, 
     "name": "bar", 
     "tags": [ 
      { 
       "tagName": "tag-a", 
       "tagColor": "orange" 
      }, 
      { 
       "tagName": "tag-b", 
       "tagColor": "red" 
      } 
     ] 
    }, 
    "3": { 
     "id": 3, 
     "name": "baz", 
     "tags": [ 
      { 
       "tagName": "tag-a", 
       "tagColor": "purple" 
      } 
     ] 
    }, 
    "4": { 
     "id": 4, 
     "name": "quix", 
     "tags": [] 
    } 
} 
+0

ありがとう@Sherifしかし、私はいくつかの他のテーブルに参加しているので、私は 'activity.id'によってテーブルを'グループ化する '必要があることを忘れていました。この場合、動作しません。 –

+0

なぜ、それは正確に動作しませんか? 'activity.id'がPKの場合、このユースケースには影響しません。 – Sherif

+0

あなたがそれがうまくいかないと主張している疑わしい 'GROUP BY'節とスキーマを含めて、それを働かせる方法を教えてください。 – Sherif

関連する問題