Задавайте вопросы, мы ответим
Вы не зашли.
Добрый день.
Есть следующая проблема.
Есть база данных с новостями к новостям(news) прикреплены фотографии (linkNews2Pic), видео (linkNews2Video) и публикации (linkNews2Smi). Необходимо вывести все новости и для каждой новости количество прикрепленных фотографий видео и публикаций.
Упрощенная структура БД
CREATE TABLE IF NOT EXISTS `news` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
);
INSERT INTO `rus_smartix_news_new` (`id`, `name`) VALUES (1, 'first'),(2, 'second'), (3, 'third');
CREATE TABLE IF NOT EXISTS `linkNews2Pic` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`newsId` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`)
);
INSERT INTO `linkNews2Pic` (`id`, `newsId`) VALUES (1, 1), (2, 1), (3, 3), (5, 3);
CREATE TABLE IF NOT EXISTS `linkNews2Video` (
`newsId` int(10) unsigned NOT NULL,
`videoId` int(10) unsigned NOT NULL,
PRIMARY KEY (`newsId`,`videoId`)
);
INSERT INTO `linkNews2Video` (`newsId`, `videoId`) VALUES (1, 561), (1, 563), (1, 564), (2, 556), (3, 563), (3, 565);
CREATE TABLE IF NOT EXISTS `linkNews2Smi` (
`newsId` int(10) unsigned NOT NULL,
`smiId` int(10) unsigned NOT NULL,
PRIMARY KEY (`newsId`,`smiId`)
);
INSERT INTO `linkNews2Smi` (`newsId`, `smiId`) VALUES (1, 3), (1, 4);
Все что приходило в голову работало только если связывать новость только с фотографиями. В этом случае работало замечательно через
SELECT n.name, count(p.id) photoNum
FROM `new` n
LEFT JOIN linkNews2Pic p ON p.newsId = n.id
GROUP BY n.id
но при добавлении еще join-ов - данные получаются неверными. Почему получается не так - понимаю, но вот как исправить - не пойму. Подскажите пожалуйста
Для проверки должно возвращать
first 2 3 2
second 0 1 0
third 2 2 1
Неактивен
напишите в лефтджойне не название таблицы, а селект с количество видео/фото/новостей примерно так
LEFT JOIN (SELECT newsId, count(videoId) FROM `linkNews2Video` GROUP BY newsId) t ON t.newsId = n.id
и так еще два джойна. должно заработать
Отредактированно Altukhov (26.01.2011 17:52:05)
Неактивен
Спасибо большое. Хотелось бы узнать или это единственный способ?
Неактивен
можно еще примерно так) т.е. для каждой таблицы опять же вывести отдельно количество строк для каждого айдишника. наверное так будет лучше, у вас не такой сложный запрос, чтоб лефтджойн писать. может и ошибаюсь.
select n.num, v1.video, p1.pict, s1.smi from news n,
(select v.id,count(v.video) as video from video v group by v.id) v1,
(select p.id,count(p.pict) as pict from pict p group by p.id) p1,
(select s.id,count(s.smi) as smi from smi s group by s.id) s1
where n.id = v1.id
and n.id = p1.id
and n.id = s1.id
Неактивен
Последний вариант мне нравится больше. Левые объединения не стоит
использовать там, где они не нужны.
Но я бы пошел еще дальше, и не считал бы большие вложенные запросы,
а заменил бы их на коротенькие:
SELECT n.*, (SELECT COUNT(*) FROM video WHERE newsID = n.id) AS video_count, ...
FROM news n;
Неактивен
А можно пойти еще дальше и сделать так
select n.num, count( distinct v.video), count(distinct p.pict), count(distinct s.smi)
from news n, video v, pict p, smi s
where n.id = v.id
and n.id = p.id
and n.id = s.id
group by n.num
не знаю как в мускуле, но в оракле работает
Неактивен
Должно работать, да. А вот как обработается DISTINCT — не знаю.
COUNT(*) по индексу просто посчитает количество дочерних эле-
ментов в индексе, а DISTINCT вполне таки может вытащить все, а
потом посортировать. Но способ красивый и понятный, мне нравится
Неактивен
Огромное всем спасибо
Неактивен