Как я могу получить mysql для получения среднего рейтинга вместе с поиском по тегам? - PullRequest
0 голосов
/ 27 мая 2011

Я пытаюсь обдумать сложное утверждение MySQL (в любом случае, сложное для меня!) По сути, мне нужно вернуть список всех продуктов из таблицы продуктов. с дополнительным возвращаемым значением (их соответствующим рейтингом звезды (таблица рейтинга), который должен быть рассчитан в среднем от общего количества всех оценок этого продукта).

Заявление sql также должно включать возможность фильтрации продуктов на основе несколько «теговых» слов, например, поиск по всем связанным товарам (через таблицу product_tags к таблице тегов) к словам, указанным при построении SQL заявление. Итак, если мне нужно было найти продукты, которые имеют теги «красный» и «белый», результаты будут возвращать продукты 1 и 3 с их соответствующим средним рейтингом.

Ниже приведен дамп sql примеров таблиц.

DROP TABLE IF EXISTS `product_tags`;
DROP TABLE IF EXISTS `rating`;
DROP TABLE IF EXISTS `tags`;
DROP TABLE IF EXISTS `products`;
CREATE TABLE IF NOT EXISTS `products` (
  `product_id` int(11) NOT NULL AUTO_INCREMENT,
  `product_name` varchar(255) CHARACTER SET latin1 NOT NULL,
  `date_added` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`product_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;

INSERT INTO `products` (`product_id`, `product_name`, `date_added`) VALUES
(1, 'first item', '2011-05-26 21:56:06'),
(2, 'second item', '2011-05-26 21:56:06'),
(3, 'third item', '2011-05-26 21:56:06');


CREATE TABLE IF NOT EXISTS `product_tags` (
  `product_id` int(10) unsigned NOT NULL,
  `tag_id` int(10) unsigned NOT NULL,
  KEY `product_id` (`product_id`),
  KEY `tag_id` (`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `product_tags` (`product_id`, `tag_id`) VALUES
(1, 4),
(1, 1),
(1, 8),
(2, 3),
(2, 9),
(3, 8),
(3, 7),
(1, 6),
(2, 5),
(3, 2),
(3, 10);

CREATE TABLE IF NOT EXISTS `rating` (
  `product_id` int(11) NOT NULL,
  `rating` float NOT NULL,
  KEY `product_id` (`product_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `rating` (`product_id`, `rating`) VALUES
(1, 5),
(1, 0),
(2, 3),
(2, 4.5),
(1, 2),
(2, 4);

CREATE TABLE IF NOT EXISTS `tags` (
  `tag_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `tag_name` varchar(50) NOT NULL,
  PRIMARY KEY (`tag_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=11 ;

INSERT INTO `tags` (`tag_id`, `tag_name`) VALUES
(1, 'red'),
(2, 'green'),
(3, 'yellow'),
(4, 'cyan'),
(5, 'blue'),
(6, 'pink'),
(7, 'purple'),
(8, 'grey'),
(9, 'black'),
(10, 'white');

ALTER TABLE `product_tags`
  ADD CONSTRAINT `product_tags_ibfk_2` FOREIGN KEY (`tag_id`) REFERENCES `product_tags` (`tag_id`) ON DELETE CASCADE ON UPDATE CASCADE,
  ADD CONSTRAINT `product_tags_ibfk_1` FOREIGN KEY (`product_id`) REFERENCES `product_tags` (`product_id`) ON DELETE CASCADE ON UPDATE CASCADE;

ALTER TABLE `rating`
  ADD CONSTRAINT `rating_ibfk_1` FOREIGN KEY (`product_id`) REFERENCES `products` (`product_id`) ON DELETE CASCADE ON UPDATE CASCADE;

Ответы [ 3 ]

3 голосов
/ 27 мая 2011
SELECT  
    p.product_id
  , p.product_name
  , p.date_added
  , ( SELECT AVG(r.rating) 
      FROM rating r
      WHERE r.product_id = p.product_id
    )
    AS avg_rating 
FROM
  products p
    JOIN
  product_tags pt
      ON pt.product_id = p.product_id
    JOIN
  tags t
      ON t.tag_id = pt.tag_id
WHERE
    t.tag_name IN ('red','white')
GROUP BY
    p.product_id

Как примечание, лучше использовать единственное число для имен таблиц. product, tag, product_tag (например, rating, который уже в единственном числе), а не множественное число, как вы: products и т. Д.

1 голос
/ 27 мая 2011
select 
  p.product_id
  , p.product_name
  , group_concat(distinct tag_name) as tags
  , ifnull(avg(r.rating),'no rating') as avg_rating 
from products p
left join rating r on (r.product_id = p.product_id)
inner join product_tags pt on (pt.product_id = p.product_id)
inner join tags t on (t.tag_id = pt.tag_id)
where tag_name in ('red','white')
group by p.product_id

Результат:

1, 'first item', 'red', '2.33333333333333'
3, 'third item', 'white', 'no rating'
1 голос
/ 27 мая 2011
SELECT `products`.`product_id`, `product_name`, `date_added`,
       AVG(`rating`) avg_rating,
       GROUP_CONCAT(`tags`.`tag_name`) all_tags
  FROM `products`
  JOIN `product_tags` ON `products`.`product_id` = `product_tags`.`product_id`
  JOIN `tags` ON `product_tags`.`tag_id` = `tags`.`tag_id`
  LEFT JOIN `rating` ON `products`.`product_id` = `rating`.`product_id`
 WHERE `tags`.`tag_name` in (?)
 GROUP BY `products`.`product_id`
...