Имеем города
Имеем пользователей
таблицы
1 - city
id name
2 - users
id name city
Нужно выбрать все города и рядом с каждым городом вывести цифрой кол-во юзеров которые отмечены в данном городе.
Т.к. опыта маловато то первым делом приходит на ум запрос в цикле. Но так оч много запросов получается.
$sql_result = mysql_query("SELECT * FROM city");
while ($row = mysql_fetch_assoc($sql_result)) {
$sql_result1 = mysql_query("SELECT city FROM users WHERE city='".$row['id']."'");
$count = mysql_num_rows($sql_result1);
$content .="$row['name'] - $count";
}
Как это будет выглядеть через COUNT и LEFT JOIN одним запросом? Как не пытался что то не получается.
Имеем пользователей
таблицы
1 - city
id name
2 - users
id name city
Нужно выбрать все города и рядом с каждым городом вывести цифрой кол-во юзеров которые отмечены в данном городе.
Т.к. опыта маловато то первым делом приходит на ум запрос в цикле. Но так оч много запросов получается.
$sql_result = mysql_query("SELECT * FROM city");
while ($row = mysql_fetch_assoc($sql_result)) {
$sql_result1 = mysql_query("SELECT city FROM users WHERE city='".$row['id']."'");
$count = mysql_num_rows($sql_result1);
$content .="$row['name'] - $count";
}
Как это будет выглядеть через COUNT и LEFT JOIN одним запросом? Как не пытался что то не получается.
SELECT city.name, (SELECT COUNT(*) FROM users WHERE users.city=city.id) AS number FROM city
Как вариант:
SELECT COUNT(users.id), city.name FROM city LEFT JOIN users ON city.id=users.city GROUP BY city.id;
Хотя получится не слишком быстро.
upd:
CREATE TABLE `city` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `users` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(255) NOT NULL,
`city` int(11) default NULL,
PRIMARY KEY (`id`),
KEY `city` (`city`)
);
SELECT COUNT(users.id), city.name FROM city FORCE INDEX (PRIMARY) LEFT JOIN users ON city.id=users.city GROUP BY city.id;
Вот так вполне себе быстро.
Ни один из предложенных выше трех вариантов не "катит"?
SELECT COUNT(users.user_id) AS count, city.* FROM users, city WHERE city.id = users.city GROUP BY city.id
Странно что-то. Города-то другие точно есть?
Если не трудно для закрепления объясните как это работает?
именно непонятно про индексы
Вариант Джей Ди выбирает таблицу city целиком и (условно) для каждой строки делает запрос, считая число пользователей в этом городе. Для обеспечения быстродействия этого всего хорошо бы создать индекс для users.city (хотя, если там ~50-100 пользователей, на обычно это можно "забить").
Мой вариант к таблице city подцепляет соответствующие значения из users и считает там количество не-NULL. Если интересно, посмотрите на результат запроса SELECT users.name, сity.name FROM city LEFT JOIN users ON city.id=users.city. Тут опять индекс по users.city, и FORCE INDEX (PRIMARY), чтобы city читалась по индексу (что избавляет сервер от необходимости создавать временную таблицу под этот запрос).
Я так понял FORCE INDEX (PRIMARY) обращается сразу к users.city если city имеет INDEX а не ко всей таблице?
Почему мы группируем вконце GROUP BY city.id?
dev.mysql.com/doc/refman/5.0/en/mysql-indexes.h...
dev.mysql.com/doc/refman/5.0/en/index-hints.htm...
www.mysql.ru/docs/man/EXPLAIN.html
по производительности пока сказать не могу.
По поводу доп строки ключа. много раз замечал что со временем цифры показывать начинают не верные значения.. и тогда приходится писать доп функцию для перерасчета.
а тут все просто и напрямю.. + кэширование никто не отменял
Если много пользователей то можно спокойно забить на триггеры и т.д. И просто раз в день делать:
UPDATE city SET number=(SELECT COUNT(*) FROM users WHERE users.city=city.id)
P.S. Кстати, если уж совсем гнаться за производительностью то лучше не пользоваться счетчиками отличными от COUNT(*), почитайте на форумах.