1

I have 4 tables: 1 item table, 1 category table, 1 item_to_category table, and a review table which holds review of each item.

An item can be in many categories.

I want to get a PHP array, which lists each item, the categories the item is in, and the number of review the item has.

Is this possible using a single database call?

This query

    $q = 'SELECT `items`.`id` as item_id, `category`.`id` as category_id, COUNT(`review_id`) AS review_count
    FROM  `items`
    JOIN  `item_to_category` ON  `item_to_category`.`item_id` =  `items`.`id`
    JOIN  `category` ON  `category`.`id` =  `item_to_category`.`id`
    JOIN  `reviews` ON `items`.`id` = `reviews`.`item_id`
    WHERE `items`.`type` = 3
    GROUP BY `items`.`id`

returns a row like this:

item_id    category_id    review_count
1          CAT1           4
2          CAT3           2

The problem is that, my review count is being multiplied by the number of categories the item is in, but the query is only returning one category.

Can anyone help?

I basically want my php array to be like:

array(
    [0] => array(
        "item_id"=1,
        "categories"=>array("CAT1","CAT3"),
        "review_count"=>2
     )
    [1] => etc
)

ADDITION: I've followed the suggestion by Mike Brant and it is an improvement, but it is not working 100% correctly. The output of the query is this:

item_id    category_id            review_count
1          CAT1,CAT2,CAT2,CAT1    4   <--- Incorrect number of reviews. Actual number is 2
2          CAT3,CAT3              2   <--- Correct number of reviews.
3          CAT1,CAT1,CAT1         3   <--- Correct number of reviews.

So basically, the returned number of reviews is correct only if the item is in 1 category. The returned categories are almost correct, but they are being duplicated by the actual number of reviews.

If I remove the JOIN on the reviews table, I get 100% correct categories, and if I remove the JOIN on the categories, I get 100% review counts.

Can anyone explain what is going on here? Thanks

4

1 に答える 1

3

これを行うには、MySQLのGROUP_CONCAT機能を利用することをお勧めします。

SELECT `items`.`id` as item_id, GROUP_CONCAT(DISTINCT `category`.`id`) as categories, COUNT(DISTINCT `reviews`.`review_id`) AS review_count
FROM  `items`
JOIN  `item_to_category` ON  `item_to_category`.`item_id` =  `items`.`id`
JOIN  `category` ON  `category`.`id` =  `item_to_category`.`id`
JOIN  `reviews` ON `items`.`id` = `reviews`.`item_id`
WHERE `items`.`type` = 3
GROUP BY `items`.`id`

これにより、結果セットは次のようになります。

item_id    category_id    review_count
1          CAT1,CAT2      4
2          CAT3,CAT4      2

次に、結果セットをループしているときに、を介してGROUP_CONCAT値を配列に変換できますexplode()

すなわち

$result_array = array();
while($row = [WHATEVER YOUR DB FUNCTION IS HERE]) {
    $row['categories'] = explode(',', $row['categories']);
    $result_array = $row;
}

アップデート:

カテゴリIDとレビュー数の重複で問題が発生しているようです。上記のクエリを更新してDISTINCTキーワードを利用しました。これで問題が解決するはずです。

于 2013-03-15T17:55:08.633 に答える